Added internal statistics to gc::DHP
[libcds.git] / cds / gc / hp.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above copyright notice,
16       this list of conditions and the following disclaimer in the documentation
17       and/or other materials provided with the distribution.
18
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef CDSLIB_GC_HP_SMR_H
32 #define CDSLIB_GC_HP_SMR_H
33
34 #include <exception>
35 #include <cds/gc/details/hp_common.h>
36 #include <cds/details/lib.h>
37 #include <cds/threading/model.h>
38 #include <cds/details/throw_exception.h>
39 #include <cds/details/static_functor.h>
40 #include <cds/details/marked_ptr.h>
41 #include <cds/user_setup/cache_line.h>
42
43 /**
44     @page cds_garbage_collectors_comparison Hazard Pointer SMR implementations
45     @ingroup cds_garbage_collector
46
47     <table>
48         <tr>
49             <th>Feature</th>
50             <th>%cds::gc::HP</th>
51             <th>%cds::gc::DHP</th>
52         </tr>
53         <tr>
54             <td>Max number of guarded (hazard) pointers per thread</td>
55             <td>limited (specified at construction time)</td>
56             <td>unlimited (dynamically allocated when needed)</td>
57         </tr>
58         <tr>
59             <td>Max number of retired pointers<sup>1</sup></td>
60             <td>bounded, specified at construction time</td>
61             <td>bounded, adaptive, depends on current thread count and number of hazard pointer for each thread</td>
62         </tr>
63         <tr>
64             <td>Thread count</td>
65             <td>bounded, upper bound is specified at construction time</td>
66             <td>unbounded</td>
67         </tr>
68     </table>
69
70     <sup>1</sup>Unbounded count of retired pointers means a possibility of memory exhaustion.
71 */
72
73 namespace cds {
74     /// @defgroup cds_garbage_collector Garbage collectors
75
76
77     /// Different safe memory reclamation schemas (garbage collectors)
78     /** @ingroup cds_garbage_collector
79
80         This namespace specifies different safe memory reclamation (SMR) algorithms.
81         See \ref cds_garbage_collector "Garbage collectors"
82     */
83     namespace gc {
84     } // namespace gc
85
86 } // namespace cds
87
88
89 namespace cds { namespace gc {
90     /// Hazard pointer implementation details
91     namespace hp {
92         using namespace cds::gc::hp::common;
93
94         /// Exception "Not enough Hazard Pointer"
95         class not_enought_hazard_ptr: public std::length_error
96         {
97         //@cond
98         public:
99             not_enought_hazard_ptr()
100                 : std::length_error( "Not enough Hazard Pointer" )
101             {}
102         //@endcond
103         };
104
105         /// Exception "Hazard Pointer SMR is not initialized"
106         class not_initialized: public std::runtime_error
107         {
108         //@cond
109         public:
110             not_initialized()
111                 : std::runtime_error( "Global Hazard Pointer SMR object is not initialized" )
112             {}
113         //@endcond
114         };
115
116         //@cond
117         /// Per-thread hazard pointer storage
118         class thread_hp_storage {
119         public:
120             thread_hp_storage( guard* arr, size_t nSize ) CDS_NOEXCEPT
121                 : free_head_( arr )
122                 , array_( arr )
123                 , capacity_( nSize )
124 #       ifdef CDS_ENABLE_HPSTAT
125                 , alloc_guard_count_(0)
126                 , free_guard_count_(0)
127 #       endif
128             {
129                 // Initialize guards
130                 new( arr ) guard[nSize];
131
132                 for ( guard* pEnd = arr + nSize - 1; arr < pEnd; ++arr )
133                     arr->next_ = arr + 1;
134                 arr->next_ = nullptr;
135             }
136
137             thread_hp_storage() = delete;
138             thread_hp_storage( thread_hp_storage const& ) = delete;
139             thread_hp_storage( thread_hp_storage&& ) = delete;
140
141             size_t capacity() const CDS_NOEXCEPT
142             {
143                 return capacity_;
144             }
145
146             bool full() const CDS_NOEXCEPT
147             {
148                 return free_head_ == nullptr;
149             }
150
151             guard* alloc()
152             {
153 #       ifdef CDS_DISABLE_SMR_EXCEPTION
154                 assert( !full());
155 #       else
156                 if ( full() )
157                     CDS_THROW_EXCEPTION( not_enought_hazard_ptr());
158 #       endif
159                 guard* g = free_head_;
160                 free_head_ = g->next_;
161                 CDS_HPSTAT( ++alloc_guard_count_ );
162                 return g;
163             }
164
165             void free( guard* g ) CDS_NOEXCEPT
166             {
167                 assert( g >= array_ && g < array_ + capacity() );
168
169                 if ( g ) {
170                     g->clear();
171                     g->next_ = free_head_;
172                     free_head_ = g;
173                     CDS_HPSTAT( ++free_guard_count_ );
174                 }
175             }
176
177             template< size_t Capacity>
178             size_t alloc( guard_array<Capacity>& arr )
179             {
180                 size_t i;
181                 guard* g = free_head_;
182                 for ( i = 0; i < Capacity && g; ++i ) {
183                     arr.reset( i, g );
184                     g = g->next_;
185                 }
186
187 #       ifdef CDS_DISABLE_SMR_EXCEPTION
188                 assert( i == Capacity );
189 #       else
190                 if ( i != Capacity )
191                     CDS_THROW_EXCEPTION( not_enought_hazard_ptr());
192 #       endif
193                 free_head_ = g;
194                 CDS_HPSTAT( alloc_guard_count_ += Capacity );
195                 return i;
196             }
197
198             template <size_t Capacity>
199             void free( guard_array<Capacity>& arr ) CDS_NOEXCEPT
200             {
201                 guard* gList = free_head_;
202                 for ( size_t i = 0; i < Capacity; ++i ) {
203                     guard* g = arr[i];
204                     if ( g ) {
205                         g->clear();
206                         g->next_ = gList;
207                         gList = g;
208                         CDS_HPSTAT( ++free_guard_count_ );
209                     }
210                 }
211                 free_head_ = gList;
212             }
213
214             // cppcheck-suppress functionConst
215             void clear()
216             {
217                 for ( guard* cur = array_, *last = array_ + capacity(); cur < last; ++cur )
218                     cur->clear();
219             }
220
221             guard& operator[]( size_t idx )
222             {
223                 assert( idx < capacity() );
224
225                 return array_[idx];
226             }
227
228             static size_t calc_array_size( size_t capacity )
229             {
230                 return sizeof( guard ) * capacity;
231             }
232
233         private:
234             guard*          free_head_; ///< Head of free guard list
235             guard* const    array_;     ///< HP array
236             size_t const    capacity_;  ///< HP array capacity
237 #       ifdef CDS_ENABLE_HPSTAT
238         public:
239             size_t          alloc_guard_count_;
240             size_t          free_guard_count_;
241 #       endif
242         };
243         //@endcond
244
245         //@cond
246         /// Per-thread retired array
247         class retired_array
248         {
249         public:
250             retired_array( retired_ptr* arr, size_t capacity ) CDS_NOEXCEPT
251                 : current_( arr )
252                 , last_( arr + capacity )
253                 , retired_( arr )
254 #       ifdef CDS_ENABLE_HPSTAT
255                 , retire_call_count_(0)
256 #       endif
257             {}
258
259             retired_array() = delete;
260             retired_array( retired_array const& ) = delete;
261             retired_array( retired_array&& ) = delete;
262
263             size_t capacity() const CDS_NOEXCEPT
264             {
265                 return last_ - retired_;
266             }
267
268             size_t size() const CDS_NOEXCEPT
269             {
270                 return current_ - retired_;
271             }
272
273             bool push( retired_ptr&& p ) CDS_NOEXCEPT
274             {
275                 *current_ = p;
276                 CDS_HPSTAT( ++retire_call_count_ );
277                 return ++current_ < last_;
278             }
279
280             retired_ptr* first() const CDS_NOEXCEPT
281             {
282                 return retired_;
283             }
284
285             retired_ptr* last() const CDS_NOEXCEPT
286             {
287                 return current_;
288             }
289
290             void reset( size_t nSize ) CDS_NOEXCEPT
291             {
292                 current_ = first() + nSize;
293             }
294
295             bool full() const CDS_NOEXCEPT
296             {
297                 return current_ == last_;
298             }
299
300             static size_t calc_array_size( size_t capacity )
301             {
302                 return sizeof( retired_ptr ) * capacity;
303             }
304
305         private:
306             retired_ptr*            current_;
307             retired_ptr* const      last_;
308             retired_ptr* const      retired_;
309 #       ifdef CDS_ENABLE_HPSTAT
310         public:
311             size_t  retire_call_count_;
312 #       endif
313         };
314         //@endcond
315
316         /// Internal statistics
317         struct stat {
318             size_t  guard_allocated;    ///< Count of allocated HP guards
319             size_t  guard_freed;        ///< Count of freed HP guards
320             size_t  retired_count;      ///< Count of retired pointers
321             size_t  free_count;         ///< Count of free pointers
322             size_t  scan_count;         ///< Count of \p scan() call
323             size_t  help_scan_count;    ///< Count of \p help_scan() call
324
325             size_t  thread_rec_count;   ///< Count of thread records
326
327             /// Default ctor
328             stat()
329             {
330                 clear();
331             }
332
333             /// Clears all counters
334             void clear()
335             {
336                 guard_allocated =
337                     guard_freed =
338                     retired_count =
339                     free_count =
340                     scan_count =
341                     help_scan_count =
342                     thread_rec_count = 0;
343             }
344         };
345
346         //@cond
347         /// Per-thread data
348         struct thread_data {
349             thread_hp_storage   hazards_;   ///< Hazard pointers private to the thread
350             retired_array       retired_;   ///< Retired data private to the thread
351
352             stat                stat_;      ///< Internal statistics for the thread
353
354             char pad1_[cds::c_nCacheLineSize];
355             atomics::atomic<unsigned int> sync_; ///< dummy var to introduce synchronizes-with relationship between threads
356             char pad2_[cds::c_nCacheLineSize];
357
358             // CppCheck warn: pad1_ and pad2_ is uninitialized in ctor
359             // cppcheck-suppress uninitMemberVar
360             thread_data( guard* guards, size_t guard_count, retired_ptr* retired_arr, size_t retired_capacity )
361                 : hazards_( guards, guard_count )
362                 , retired_( retired_arr, retired_capacity )
363                 , sync_(0)
364             {}
365
366             thread_data() = delete;
367             thread_data( thread_data const& ) = delete;
368             thread_data( thread_data&& ) = delete;
369
370             void sync()
371             {
372                 sync_.fetch_add( 1, atomics::memory_order_acq_rel );
373             }
374         };
375         //@endcond
376
377         /// \p smr::scan() strategy
378         enum scan_type {
379             classic,    ///< classic scan as described in Michael's works (see smr::classic_scan() )
380             inplace     ///< inplace scan without allocation (see smr::inplace_scan() )
381         };
382
383         //@cond
384         /// Hazard Pointer SMR (Safe Memory Reclamation)
385         class smr
386         {
387             struct thread_record;
388
389         public:
390             /// Returns the instance of Hazard Pointer \ref smr
391             static smr& instance()
392             {
393 #       ifdef CDS_DISABLE_SMR_EXCEPTION
394                 assert( instance_ != nullptr );
395 #       else
396                 if ( !instance_ )
397                     CDS_THROW_EXCEPTION( not_initialized());
398 #       endif
399                 return *instance_;
400             }
401
402             /// Creates Hazard Pointer SMR singleton
403             /**
404                 Hazard Pointer SMR is a singleton. If HP instance is not initialized then the function creates the instance.
405                 Otherwise it does nothing.
406
407                 The Michael's HP reclamation schema depends of three parameters:
408                 - \p nHazardPtrCount - HP pointer count per thread. Usually it is small number (2-4) depending from
409                     the data structure algorithms. By default, if \p nHazardPtrCount = 0,
410                     the function uses maximum of HP count for CDS library
411                 - \p nMaxThreadCount - max count of thread with using HP GC in your application. Default is 100.
412                 - \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
413                     <tt> nHazardPtrCount * nMaxThreadCount </tt>
414                     Default is <tt>2 * nHazardPtrCount * nMaxThreadCount</tt>
415             */
416             static CDS_EXPORT_API void construct(
417                 size_t nHazardPtrCount = 0,     ///< Hazard pointer count per thread
418                 size_t nMaxThreadCount = 0,     ///< Max count of simultaneous working thread in your application
419                 size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
420                 scan_type nScanType = inplace   ///< Scan type (see \ref scan_type enum)
421             );
422
423             // for back-copatibility
424             static void Construct(
425                 size_t nHazardPtrCount = 0,     ///< Hazard pointer count per thread
426                 size_t nMaxThreadCount = 0,     ///< Max count of simultaneous working thread in your application
427                 size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
428                 scan_type nScanType = inplace   ///< Scan type (see \ref scan_type enum)
429             )
430             {
431                 construct( nHazardPtrCount, nMaxThreadCount, nMaxRetiredPtrCount, nScanType );
432             }
433
434             /// Destroys global instance of \ref smr
435             /**
436                 The parameter \p bDetachAll should be used carefully: if its value is \p true,
437                 then the object destroyed automatically detaches all attached threads. This feature
438                 can be useful when you have no control over the thread termination, for example,
439                 when \p libcds is injected into existing external thread.
440             */
441             static CDS_EXPORT_API void destruct(
442                 bool bDetachAll = false     ///< Detach all threads
443             );
444
445             // for back-compatibility
446             static void Destruct(
447                 bool bDetachAll = false     ///< Detach all threads
448             )
449             {
450                 destruct( bDetachAll );
451             }
452
453             /// Checks if global SMR object is constructed and may be used
454             static bool isUsed() CDS_NOEXCEPT
455             {
456                 return instance_ != nullptr;
457             }
458
459             /// Set memory management functions
460             /**
461                 @note This function may be called <b>BEFORE</b> creating an instance
462                 of Hazard Pointer SMR
463
464                 SMR object allocates some memory for thread-specific data and for
465                 creating SMR object.
466                 By default, a standard \p new and \p delete operators are used for this.
467             */
468             static CDS_EXPORT_API void set_memory_allocator(
469                 void* ( *alloc_func )( size_t size ),
470                 void (*free_func )( void * p )
471             );
472
473             /// Returns max Hazard Pointer count per thread
474             size_t get_hazard_ptr_count() const CDS_NOEXCEPT
475             {
476                 return hazard_ptr_count_;
477             }
478
479             /// Returns max thread count
480             size_t get_max_thread_count() const CDS_NOEXCEPT
481             {
482                 return max_thread_count_;
483             }
484
485             /// Returns max size of retired objects array
486             size_t get_max_retired_ptr_count() const CDS_NOEXCEPT
487             {
488                 return max_retired_ptr_count_;
489             }
490
491             /// Get current scan strategy
492             scan_type get_scan_type() const
493             {
494                 return scan_type_;
495             }
496
497             /// Checks that required hazard pointer count \p nRequiredCount is less or equal then max hazard pointer count
498             /**
499                 If <tt> nRequiredCount > get_hazard_ptr_count()</tt> then the exception \p not_enought_hazard_ptr is thrown
500             */
501             static void check_hazard_ptr_count( size_t nRequiredCount )
502             {
503                 if ( instance().get_hazard_ptr_count() < nRequiredCount ) {
504 #       ifdef CDS_DISABLE_SMR_EXCEPTION
505                     assert( false );    // not enough hazard ptr
506 #       else
507                     CDS_THROW_EXCEPTION( not_enought_hazard_ptr() );
508 #       endif
509                 }
510             }
511
512             /// Returns thread-local data for the current thread
513             static CDS_EXPORT_API thread_data* tls();
514
515             static CDS_EXPORT_API void attach_thread();
516             static CDS_EXPORT_API void detach_thread();
517
518             /// Get internal statistics
519             void statistics( stat& st );
520
521         public: // for internal use only
522             /// The main garbage collecting function
523             /**
524                 This function is called internally when upper bound of thread's list of reclaimed pointers
525                 is reached.
526
527                 There are the following scan algorithm:
528                 - \ref hzp_gc_classic_scan "classic_scan" allocates memory for internal use
529                 - \ref hzp_gc_inplace_scan "inplace_scan" does not allocate any memory
530
531                 Use \p set_scan_type() member function to setup appropriate scan algorithm.
532             */
533             void scan( thread_data* pRec )
534             {
535                 ( this->*scan_func_ )( pRec );
536             }
537
538             /// Helper scan routine
539             /**
540                 The function guarantees that every node that is eligible for reuse is eventually freed, barring
541                 thread failures. To do so, after executing \p scan(), a thread executes a \p %help_scan(),
542                 where it checks every HP record. If an HP record is inactive, the thread moves all "lost" reclaimed pointers
543                 to thread's list of reclaimed pointers.
544
545                 The function is called internally by \p scan().
546             */
547             CDS_EXPORT_API void help_scan( thread_data* pThis );
548
549         private:
550             CDS_EXPORT_API smr(
551                 size_t nHazardPtrCount,     ///< Hazard pointer count per thread
552                 size_t nMaxThreadCount,     ///< Max count of simultaneous working thread in your application
553                 size_t nMaxRetiredPtrCount, ///< Capacity of the array of retired objects for the thread
554                 scan_type nScanType         ///< Scan type (see \ref scan_type enum)
555             );
556
557             CDS_EXPORT_API ~smr();
558
559             CDS_EXPORT_API void detach_all_thread();
560
561             /// Classic scan algorithm
562             /** @anchor hzp_gc_classic_scan
563                 Classical scan algorithm as described in Michael's paper.
564
565                 A scan includes four stages. The first stage involves scanning the array HP for non-null values.
566                 Whenever a non-null value is encountered, it is inserted in a local list of currently protected pointer.
567                 Only stage 1 accesses shared variables. The following stages operate only on private variables.
568
569                 The second stage of a scan involves sorting local list of protected pointers to allow
570                 binary search in the third stage.
571
572                 The third stage of a scan involves checking each reclaimed node
573                 against the pointers in local list of protected pointers. If the binary search yields
574                 no match, the node is freed. Otherwise, it cannot be deleted now and must kept in thread's list
575                 of reclaimed pointers.
576
577                 The forth stage prepares new thread's private list of reclaimed pointers
578                 that could not be freed during the current scan, where they remain until the next scan.
579
580                 This algorithm allocates memory for internal HP array.
581
582                 This function is called internally by ThreadGC object when upper bound of thread's list of reclaimed pointers
583                 is reached.
584             */
585             CDS_EXPORT_API void classic_scan( thread_data* pRec );
586
587             /// In-place scan algorithm
588             /** @anchor hzp_gc_inplace_scan
589                 Unlike the \p classic_scan() algorithm, \p %inplace_scan() does not allocate any memory.
590                 All operations are performed in-place.
591             */
592             CDS_EXPORT_API void inplace_scan( thread_data* pRec );
593
594         private:
595             CDS_EXPORT_API thread_record* create_thread_data();
596             static CDS_EXPORT_API void destroy_thread_data( thread_record* pRec );
597
598             /// Allocates Hazard Pointer SMR thread private data
599             CDS_EXPORT_API thread_record* alloc_thread_data();
600
601             /// Free HP SMR thread-private data
602             CDS_EXPORT_API void free_thread_data( thread_record* pRec );
603
604         private:
605             static CDS_EXPORT_API smr* instance_;
606
607             atomics::atomic< thread_record*>    thread_list_;   ///< Head of thread list
608
609             size_t const    hazard_ptr_count_;      ///< max count of thread's hazard pointer
610             size_t const    max_thread_count_;      ///< max count of thread
611             size_t const    max_retired_ptr_count_; ///< max count of retired ptr per thread
612             scan_type const scan_type_;             ///< scan type (see \ref scan_type enum)
613             void ( smr::*scan_func_ )( thread_data* pRec );
614         };
615         //@endcond
616
617         //@cond
618         // for backward compatibility
619         typedef smr GarbageCollector;
620         //@endcond
621
622     } // namespace hp
623
624     /// Hazard Pointer SMR (Safe Memory Reclamation)
625     /**  @ingroup cds_garbage_collector
626
627         Implementation of classic Hazard Pointer SMR
628
629         Sources:
630             - [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
631             - [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
632             - [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
633
634         Hazard Pointer SMR is a singleton. The main user-level part of Hazard Pointer schema is
635         \p %cds::gc::HP class and its nested classes. Before use any HP-related class you must initialize \p %HP
636         by contructing \p %cds::gc::HP object in beginning of your \p main().
637         See \ref cds_how_to_use "How to use" section for details how to apply SMR schema.
638     */
639     class HP
640     {
641     public:
642         /// Native guarded pointer type
643         typedef hp::hazard_ptr guarded_pointer;
644
645         /// Atomic reference
646         template <typename T> using atomic_ref = atomics::atomic<T *>;
647
648         /// Atomic marked pointer
649         template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
650
651         /// Atomic type
652         template <typename T> using atomic_type = atomics::atomic<T>;
653
654         /// Exception "Not enough Hazard Pointer"
655         typedef hp::not_enought_hazard_ptr not_enought_hazard_ptr_exception;
656
657         /// Internal statistics
658         typedef hp::stat stat;
659
660         /// Hazard Pointer guard
661         /**
662             A guard is a hazard pointer.
663             Additionally, the \p %Guard class manages allocation and deallocation of the hazard pointer.
664
665             \p %Guard object is movable but not copyable.
666
667             The guard object can be in two states:
668             - unlinked - the guard is not linked with any internal hazard pointer.
669               In this state no operation except \p link() and move assignment is supported.
670             - linked (default) - the guard allocates an internal hazard pointer and completely operable.
671
672             Due to performance reason the implementation does not check state of the guard in runtime.
673
674             @warning Move assignment transfers the guard in unlinked state, use with care.
675         */
676         class Guard
677         {
678         public:
679             /// Default ctor allocates a guard (hazard pointer) from thread-private storage
680             /**
681                 @warning Can throw \p too_many_hazard_ptr_exception if internal hazard pointer objects are exhausted.
682             */
683             Guard()
684                 : guard_( hp::smr::tls()->hazards_.alloc() )
685             {}
686
687             /// Initilalizes an unlinked guard i.e. the guard contains no hazard pointer. Used for move semantics support
688             explicit Guard( std::nullptr_t ) CDS_NOEXCEPT
689                 : guard_( nullptr )
690             {}
691
692             /// Move ctor - \p src guard becomes unlinked (transfer internal guard ownership)
693             Guard( Guard&& src ) CDS_NOEXCEPT
694                 : guard_( src.guard_ )
695             {
696                 src.guard_ = nullptr;
697             }
698
699             /// Move assignment: the internal guards are swapped between \p src and \p this
700             /**
701                 @warning \p src will become in unlinked state if \p this was unlinked on entry.
702             */
703             Guard& operator=( Guard&& src ) CDS_NOEXCEPT
704             {
705                 std::swap( guard_, src.guard_ );
706                 return *this;
707             }
708
709             /// Copy ctor is prohibited - the guard is not copyable
710             Guard( Guard const& ) = delete;
711
712             /// Copy assignment is prohibited
713             Guard& operator=( Guard const& ) = delete;
714
715             /// Frees the internal hazard pointer if the guard is in linked state
716             ~Guard()
717             {
718                 unlink();
719             }
720
721             /// Checks if the guard object linked with any internal hazard pointer
722             bool is_linked() const
723             {
724                 return guard_ != nullptr;
725             }
726
727             /// Links the guard with internal hazard pointer if the guard is in unlinked state
728             /**
729                 @warning Can throw \p not_enought_hazard_ptr_exception if internal hazard pointer array is exhausted.
730             */
731             void link()
732             {
733                 if ( !guard_ )
734                     guard_ = hp::smr::tls()->hazards_.alloc();
735             }
736
737             /// Unlinks the guard from internal hazard pointer; the guard becomes in unlinked state
738             void unlink()
739             {
740                 if ( guard_ ) {
741                     hp::smr::tls()->hazards_.free( guard_ );
742                     guard_ = nullptr;
743                 }
744             }
745
746             /// Protects a pointer of type \p atomic<T*>
747             /**
748                 Return the value of \p toGuard
749
750                 The function tries to load \p toGuard and to store it
751                 to the HP slot repeatedly until the guard's value equals \p toGuard
752
753                 @warning The guad object should be in linked state, otherwise the result is undefined
754             */
755             template <typename T>
756             T protect( atomics::atomic<T> const& toGuard )
757             {
758                 assert( guard_ != nullptr );
759
760                 T pCur = toGuard.load(atomics::memory_order_acquire);
761                 T pRet;
762                 do {
763                     pRet = assign( pCur );
764                     pCur = toGuard.load(atomics::memory_order_acquire);
765                 } while ( pRet != pCur );
766                 return pCur;
767             }
768
769             /// Protects a converted pointer of type \p atomic<T*>
770             /**
771                 Return the value of \p toGuard
772
773                 The function tries to load \p toGuard and to store result of \p f functor
774                 to the HP slot repeatedly until the guard's value equals \p toGuard.
775
776                 The function is useful for intrusive containers when \p toGuard is a node pointer
777                 that should be converted to a pointer to the value before protecting.
778                 The parameter \p f of type Func is a functor that makes this conversion:
779                 \code
780                     struct functor {
781                         value_type * operator()( T * p );
782                     };
783                 \endcode
784                 Actually, the result of <tt> f( toGuard.load()) </tt> is assigned to the hazard pointer.
785
786                 @warning The guad object should be in linked state, otherwise the result is undefined
787             */
788             template <typename T, class Func>
789             T protect( atomics::atomic<T> const& toGuard, Func f )
790             {
791                 assert( guard_ != nullptr );
792
793                 T pCur = toGuard.load(atomics::memory_order_acquire);
794                 T pRet;
795                 do {
796                     pRet = pCur;
797                     assign( f( pCur ));
798                     pCur = toGuard.load(atomics::memory_order_acquire);
799                 } while ( pRet != pCur );
800                 return pCur;
801             }
802
803             /// Store \p p to the guard
804             /**
805                 The function equals to a simple assignment the value \p p to guard, no loop is performed.
806                 Can be used for a pointer that cannot be changed concurrently or if the pointer is already
807                 guarded by another guard.
808
809                 @warning The guad object should be in linked state, otherwise the result is undefined
810             */
811             template <typename T>
812             T * assign( T* p )
813             {
814                 assert( guard_ != nullptr );
815
816                 guard_->set( p );
817                 hp::smr::tls()->sync();
818                 return p;
819             }
820
821             //@cond
822             std::nullptr_t assign( std::nullptr_t )
823             {
824                 assert( guard_ != nullptr );
825
826                 guard_->clear();
827                 return nullptr;
828             }
829             //@endcond
830
831             /// Copy a value guarded from \p src guard to \p this guard (valid only in linked state)
832             void copy( Guard const& src )
833             {
834                 assign( src.get_native());
835             }
836
837             /// Store marked pointer \p p to the guard
838             /**
839                 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
840                 Can be used for a marked pointer that cannot be changed concurrently or if the marked pointer
841                 is already guarded by another guard.
842
843                 @warning The guard object should be in linked state, otherwise the result is undefined
844             */
845             template <typename T, int BITMASK>
846             T * assign( cds::details::marked_ptr<T, BITMASK> p )
847             {
848                 return assign( p.ptr());
849             }
850
851             /// Clear value of the guard (valid only in linked state)
852             void clear()
853             {
854                 assign( nullptr );
855             }
856
857             /// Get the value currently protected (valid only in linked state)
858             template <typename T>
859             T * get() const
860             {
861                 assert( guard_ != nullptr );
862                 return guard_->get_as<T>();
863             }
864
865             /// Get native hazard pointer stored (valid only in linked state)
866             guarded_pointer get_native() const
867             {
868                 assert( guard_ != nullptr );
869                 return guard_->get();
870             }
871
872             //@cond
873             hp::guard* release()
874             {
875                 hp::guard* g = guard_;
876                 guard_ = nullptr;
877                 return g;
878             }
879
880             hp::guard*& guard_ref()
881             {
882                 return guard_;
883             }
884             //@endcond
885
886         private:
887             //@cond
888             hp::guard* guard_;
889             //@endcond
890         };
891
892         /// Array of Hazard Pointer guards
893         /**
894             The class is intended for allocating an array of hazard pointer guards.
895             Template parameter \p Count defines the size of the array.
896         */
897         template <size_t Count>
898         class GuardArray
899         {
900         public:
901             /// Rebind array for other size \p Count2
902             template <size_t Count2>
903             struct rebind {
904                 typedef GuardArray<Count2>  other;   ///< rebinding result
905             };
906
907             /// Array capacity
908             static CDS_CONSTEXPR const size_t c_nCapacity = Count;
909
910         public:
911             /// Default ctor allocates \p Count hazard pointers
912             GuardArray()
913             {
914                 hp::smr::tls()->hazards_.alloc( guards_ );
915             }
916
917             /// Move ctor is prohibited
918             GuardArray( GuardArray&& ) = delete;
919
920             /// Move assignment is prohibited
921             GuardArray& operator=( GuardArray&& ) = delete;
922
923             /// Copy ctor is prohibited
924             GuardArray( GuardArray const& ) = delete;
925
926             /// Copy assignment is prohibited
927             GuardArray& operator=( GuardArray const& ) = delete;
928
929             /// Frees allocated hazard pointers
930             ~GuardArray()
931             {
932                 hp::smr::tls()->hazards_.free( guards_ );
933             }
934
935             /// Protects a pointer of type \p atomic<T*>
936             /**
937                 Return the value of \p toGuard
938
939                 The function tries to load \p toGuard and to store it
940                 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
941             */
942             template <typename T>
943             T protect( size_t nIndex, atomics::atomic<T> const& toGuard )
944             {
945                 assert( nIndex < capacity());
946
947                 T pRet;
948                 do {
949                     pRet = assign( nIndex, toGuard.load(atomics::memory_order_acquire));
950                 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
951
952                 return pRet;
953             }
954
955             /// Protects a pointer of type \p atomic<T*>
956             /**
957                 Return the value of \p toGuard
958
959                 The function tries to load \p toGuard and to store it
960                 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
961
962                 The function is useful for intrusive containers when \p toGuard is a node pointer
963                 that should be converted to a pointer to the value type before guarding.
964                 The parameter \p f of type Func is a functor that makes this conversion:
965                 \code
966                     struct functor {
967                         value_type * operator()( T * p );
968                     };
969                 \endcode
970                 Really, the result of <tt> f( toGuard.load()) </tt> is assigned to the hazard pointer.
971             */
972             template <typename T, class Func>
973             T protect( size_t nIndex, atomics::atomic<T> const& toGuard, Func f )
974             {
975                 assert( nIndex < capacity());
976
977                 T pRet;
978                 do {
979                     assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_acquire)));
980                 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
981
982                 return pRet;
983             }
984
985             /// Store \p to the slot \p nIndex
986             /**
987                 The function equals to a simple assignment, no loop is performed.
988             */
989             template <typename T>
990             T * assign( size_t nIndex, T * p )
991             {
992                 assert( nIndex < capacity() );
993
994                 guards_.set( nIndex, p );
995                 hp::smr::tls()->sync();
996                 return p;
997             }
998
999             /// Store marked pointer \p p to the guard
1000             /**
1001                 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
1002                 Can be used for a marked pointer that cannot be changed concurrently.
1003             */
1004             template <typename T, int BITMASK>
1005             T * assign( size_t nIndex, cds::details::marked_ptr<T, BITMASK> p )
1006             {
1007                 return assign( nIndex, p.ptr());
1008             }
1009
1010             /// Copy guarded value from \p src guard to slot at index \p nIndex
1011             void copy( size_t nIndex, Guard const& src )
1012             {
1013                 assign( nIndex, src.get_native());
1014             }
1015
1016             /// Copy guarded value from slot \p nSrcIndex to the slot \p nDestIndex
1017             void copy( size_t nDestIndex, size_t nSrcIndex )
1018             {
1019                 assign( nDestIndex, get_native( nSrcIndex ));
1020             }
1021
1022             /// Clear value of the slot \p nIndex
1023             void clear( size_t nIndex )
1024             {
1025                 guards_.clear( nIndex );
1026             }
1027
1028             /// Get current value of slot \p nIndex
1029             template <typename T>
1030             T * get( size_t nIndex ) const
1031             {
1032                 assert( nIndex < capacity() );
1033                 return guards_[nIndex]->template get_as<T>();
1034             }
1035
1036             /// Get native hazard pointer stored
1037             guarded_pointer get_native( size_t nIndex ) const
1038             {
1039                 assert( nIndex < capacity());
1040                 return guards_[nIndex]->get();
1041             }
1042
1043             //@cond
1044             hp::guard* release( size_t nIndex ) CDS_NOEXCEPT
1045             {
1046                 return guards_.release( nIndex );
1047             }
1048             //@endcond
1049
1050             /// Capacity of the guard array
1051             static CDS_CONSTEXPR size_t capacity()
1052             {
1053                 return c_nCapacity;
1054             }
1055
1056         private:
1057             //@cond
1058             hp::guard_array<c_nCapacity> guards_;
1059             //@endcond
1060         };
1061
1062         /// Guarded pointer
1063         /**
1064             A guarded pointer is a pair of a pointer and GC's guard.
1065             Usually, it is used for returning a pointer to an element of a lock-free container.
1066             The guard prevents the pointer to be early disposed (freed) by SMR.
1067             After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time.
1068
1069             Template arguments:
1070             - \p GuardedType - a type which the guard stores
1071             - \p ValueType - a value type
1072             - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
1073
1074             For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
1075             In such case the \p %guarded_ptr is:
1076             @code
1077             typedef cds::gc::HP::guarded_ptr< foo > intrusive_guarded_ptr;
1078             @endcode
1079
1080             For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
1081             For example:
1082             @code
1083             struct foo {
1084                 int const   key;
1085                 std::string value;
1086             };
1087
1088             struct value_accessor {
1089                 std::string* operator()( foo* pFoo ) const
1090                 {
1091                     return &(pFoo->value);
1092                 }
1093             };
1094
1095             // Guarded ptr
1096             typedef cds::gc::HP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
1097             @endcode
1098
1099             You don't need use this class directly.
1100             All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
1101         */
1102         template <typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
1103         class guarded_ptr
1104         {
1105             //@cond
1106             struct trivial_cast {
1107                 ValueType * operator()( GuardedType * p ) const
1108                 {
1109                     return p;
1110                 }
1111             };
1112
1113             template <typename GT, typename VT, typename C> friend class guarded_ptr;
1114             //@endcond
1115
1116         public:
1117             typedef GuardedType guarded_type; ///< Guarded type
1118             typedef ValueType   value_type;   ///< Value type
1119
1120             /// Functor for casting \p guarded_type to \p value_type
1121             typedef typename std::conditional< std::is_same<Cast, void>::value, trivial_cast, Cast >::type value_cast;
1122
1123         public:
1124             /// Creates empty guarded pointer
1125             guarded_ptr() CDS_NOEXCEPT
1126                 : guard_(nullptr)
1127             {}
1128
1129             //@cond
1130             explicit guarded_ptr( hp::guard* g ) CDS_NOEXCEPT
1131                 : guard_( g )
1132             {}
1133
1134             /// Initializes guarded pointer with \p p
1135             explicit guarded_ptr( guarded_type* p ) CDS_NOEXCEPT
1136                 : guard_( nullptr )
1137             {
1138                 reset(p);
1139             }
1140             explicit guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
1141                 : guard_( nullptr )
1142             {}
1143             //@endcond
1144
1145             /// Move ctor
1146             guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
1147                 : guard_( gp.guard_ )
1148             {
1149                 gp.guard_ = nullptr;
1150             }
1151
1152             /// Move ctor
1153             template <typename GT, typename VT, typename C>
1154             guarded_ptr( guarded_ptr<GT, VT, C>&& gp ) CDS_NOEXCEPT
1155                 : guard_( gp.guard_ )
1156             {
1157                 gp.guard_ = nullptr;
1158             }
1159
1160             /// Ctor from \p Guard
1161             explicit guarded_ptr( Guard&& g ) CDS_NOEXCEPT
1162                 : guard_( g.release())
1163             {}
1164
1165             /// The guarded pointer is not copy-constructible
1166             guarded_ptr( guarded_ptr const& gp ) = delete;
1167
1168             /// Clears the guarded pointer
1169             /**
1170                 \ref release() is called if guarded pointer is not \ref empty()
1171             */
1172             ~guarded_ptr() CDS_NOEXCEPT
1173             {
1174                 release();
1175             }
1176
1177             /// Move-assignment operator
1178             guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
1179             {
1180                 std::swap( guard_, gp.guard_ );
1181                 return *this;
1182             }
1183
1184             /// Move-assignment from \p Guard
1185             guarded_ptr& operator=( Guard&& g ) CDS_NOEXCEPT
1186             {
1187                 std::swap( guard_, g.guard_ref());
1188                 return *this;
1189             }
1190
1191             /// The guarded pointer is not copy-assignable
1192             guarded_ptr& operator=(guarded_ptr const& gp) = delete;
1193
1194             /// Returns a pointer to guarded value
1195             value_type * operator ->() const CDS_NOEXCEPT
1196             {
1197                 assert( !empty());
1198                 return value_cast()( guard_->get_as<guarded_type>());
1199             }
1200
1201             /// Returns a reference to guarded value
1202             value_type& operator *() CDS_NOEXCEPT
1203             {
1204                 assert( !empty());
1205                 return *value_cast()( guard_->get_as<guarded_type>());
1206             }
1207
1208             /// Returns const reference to guarded value
1209             value_type const& operator *() const CDS_NOEXCEPT
1210             {
1211                 assert( !empty());
1212                 return *value_cast()( guard_->get_as<guarded_type>());
1213             }
1214
1215             /// Checks if the guarded pointer is \p nullptr
1216             bool empty() const CDS_NOEXCEPT
1217             {
1218                 return !guard_ || guard_->get( atomics::memory_order_relaxed ) == nullptr;
1219             }
1220
1221             /// \p bool operator returns <tt>!empty()</tt>
1222             explicit operator bool() const CDS_NOEXCEPT
1223             {
1224                 return !empty();
1225             }
1226
1227             /// Clears guarded pointer
1228             /**
1229                 If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
1230                 Dereferncing the guarded pointer after \p release() is dangerous.
1231             */
1232             void release() CDS_NOEXCEPT
1233             {
1234                 free_guard();
1235             }
1236
1237             //@cond
1238             // For internal use only!!!
1239             void reset(guarded_type * p) CDS_NOEXCEPT
1240             {
1241                 alloc_guard();
1242                 assert( guard_ );
1243                 guard_->set(p);
1244             }
1245             //@endcond
1246
1247         private:
1248             //@cond
1249             void alloc_guard()
1250             {
1251                 if ( !guard_ )
1252                     guard_ = hp::smr::tls()->hazards_.alloc();
1253             }
1254
1255             void free_guard()
1256             {
1257                 if ( guard_ ) {
1258                     hp::smr::tls()->hazards_.free( guard_ );
1259                     guard_ = nullptr;
1260                 }
1261             }
1262             //@endcond
1263
1264         private:
1265             //@cond
1266             hp::guard* guard_;
1267             //@endcond
1268         };
1269
1270     public:
1271         /// \p scan() type
1272         enum class scan_type {
1273             classic = hp::classic,    ///< classic scan as described in Michael's papers
1274             inplace = hp::inplace     ///< inplace scan without allocation
1275         };
1276
1277         /// Initializes %HP singleton
1278         /**
1279             The constructor initializes Hazard Pointer SMR singleton with passed parameters.
1280             If the instance does not yet exist then the function creates the instance.
1281             Otherwise it does nothing.
1282
1283             The Michael's %HP reclamation schema depends of three parameters:
1284             - \p nHazardPtrCount - hazard pointer count per thread. Usually it is small number (up to 10) depending from
1285                 the data structure algorithms. If \p nHazardPtrCount = 0, the defaul value 8 is used
1286             - \p nMaxThreadCount - max count of thread with using Hazard Pointer GC in your application. Default is 100.
1287             - \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
1288                 <tt> nHazardPtrCount * nMaxThreadCount </tt>. Default is <tt>2 * nHazardPtrCount * nMaxThreadCount </tt>.
1289         */
1290         HP(
1291             size_t nHazardPtrCount = 0,     ///< Hazard pointer count per thread
1292             size_t nMaxThreadCount = 0,     ///< Max count of simultaneous working thread in your application
1293             size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
1294             scan_type nScanType = scan_type::inplace   ///< Scan type (see \p scan_type enum)
1295         )
1296         {
1297             hp::smr::construct(
1298                 nHazardPtrCount,
1299                 nMaxThreadCount,
1300                 nMaxRetiredPtrCount,
1301                 static_cast<hp::scan_type>(nScanType)
1302             );
1303         }
1304
1305         /// Terminates GC singleton
1306         /**
1307             The destructor destroys %HP global object. After calling of this function you may \b NOT
1308             use CDS data structures based on \p %cds::gc::HP.
1309             Usually, %HP object is destroyed at the end of your \p main().
1310         */
1311         ~HP()
1312         {
1313             hp::smr::destruct( true );
1314         }
1315
1316         /// Checks that required hazard pointer count \p nCountNeeded is less or equal then max hazard pointer count
1317         /**
1318             If <tt> nRequiredCount > get_hazard_ptr_count()</tt> then the exception \p not_enought_hazard_ptr is thrown
1319         */
1320         static void check_available_guards( size_t nCountNeeded )
1321         {
1322             hp::smr::check_hazard_ptr_count( nCountNeeded );
1323         }
1324
1325         /// Set memory management functions
1326         /**
1327             @note This function may be called <b>BEFORE</b> creating an instance
1328             of Hazard Pointer SMR
1329
1330             SMR object allocates some memory for thread-specific data and for
1331             creating SMR object.
1332             By default, a standard \p new and \p delete operators are used for this.
1333         */
1334         static void set_memory_allocator(
1335             void* ( *alloc_func )( size_t size ),   ///< \p malloc() function
1336             void( *free_func )( void * p )          ///< \p free() function
1337         )
1338         {
1339             hp::smr::set_memory_allocator( alloc_func, free_func );
1340         }
1341
1342         /// Returns max Hazard Pointer count
1343         static size_t max_hazard_count()
1344         {
1345             return hp::smr::instance().get_hazard_ptr_count();
1346         }
1347
1348         /// Returns max count of thread
1349         static size_t max_thread_count()
1350         {
1351             return hp::smr::instance().get_max_thread_count();
1352         }
1353
1354         /// Returns capacity of retired pointer array
1355         static size_t retired_array_capacity()
1356         {
1357             return hp::smr::instance().get_max_retired_ptr_count();
1358         }
1359
1360         /// Retire pointer \p p with function \p func
1361         /**
1362             The function places pointer \p p to array of pointers ready for removing.
1363             (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
1364             \p func is a disposer: when \p p can be safely removed, \p func is called.
1365         */
1366         template <typename T>
1367         static void retire( T * p, void( *func )( T * ))
1368         {
1369             hp::thread_data* rec = hp::smr::tls();
1370             if ( !rec->retired_.push( hp::retired_ptr( p, func )))
1371                 hp::smr::instance().scan( rec );
1372         }
1373
1374         /// Retire pointer \p p with functor of type \p Disposer
1375         /**
1376             The function places pointer \p p to array of pointers ready for removing.
1377             (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
1378
1379             Deleting the pointer is an invocation of some object of type \p Disposer; the interface of \p Disposer is:
1380             \code
1381             template <typename T>
1382             struct disposer {
1383                 void operator()( T * p )    ;   // disposing operator
1384             };
1385             \endcode
1386             Since the functor call can happen at any time after \p retire() call, additional restrictions are imposed to \p Disposer type:
1387             - it should be stateless functor
1388             - it should be default-constructible
1389             - the result of functor call with argument \p p should not depend on where the functor will be called.
1390
1391             \par Examples:
1392             Operator \p delete functor:
1393             \code
1394             template <typename T>
1395             struct disposer {
1396                 void operator ()( T * p ) {
1397                     delete p;
1398                 }
1399             };
1400
1401             // How to call HP::retire method
1402             int * p = new int;
1403
1404             // ... use p in lock-free manner
1405
1406             cds::gc::HP::retire<disposer>( p ) ;   // place p to retired pointer array of HP GC
1407             \endcode
1408
1409             Functor based on \p std::allocator :
1410             \code
1411             template <typename Alloc = std::allocator<int> >
1412             struct disposer {
1413                 template <typename T>
1414                 void operator()( T * p ) {
1415                     typedef typename Alloc::templare rebind<T>::other alloc_t;
1416                     alloc_t a;
1417                     a.destroy( p );
1418                     a.deallocate( p, 1 );
1419                 }
1420             };
1421             \endcode
1422         */
1423         template <class Disposer, typename T>
1424         static void retire( T * p )
1425         {
1426             if ( !hp::smr::tls()->retired_.push( hp::retired_ptr( p, cds::details::static_functor<Disposer, T>::call )))
1427                 scan();
1428         }
1429
1430         /// Get current scan strategy
1431         static scan_type getScanType()
1432         {
1433             return static_cast<scan_type>( hp::smr::instance().get_scan_type());
1434         }
1435
1436         /// Checks if Hazard Pointer GC is constructed and may be used
1437         static bool isUsed()
1438         {
1439             return hp::smr::isUsed();
1440         }
1441
1442         /// Forces SMR call for current thread
1443         /**
1444             Usually, this function should not be called directly.
1445         */
1446         static void scan()
1447         {
1448             hp::smr::instance().scan( hp::smr::tls());
1449         }
1450
1451         /// Synonym for \p scan()
1452         static void force_dispose()
1453         {
1454             scan();
1455         }
1456
1457         /// Returns internal statistics
1458         /**
1459             The function clears \p st before gathering statistics.
1460
1461             @note Internal statistics is available only if you compile
1462             \p libcds and your program with \p -DCDS_ENABLE_HPSTAT key.
1463         */
1464         static void statistics( stat& st )
1465         {
1466             hp::smr::instance().statistics( st );
1467         }
1468
1469         /// Returns post-mortem statistics
1470         /**
1471             Post-mortem statistics is gathered in the \p %HP object destructor
1472             and can be accessible after destructing the global \p %HP object.
1473
1474             @note Internal statistics is available only if you compile
1475             \p libcds and your program with \p -DCDS_ENABLE_HPSTAT key.
1476
1477             Usage:
1478             \code
1479             int main()
1480             {
1481                 cds::Initialize();
1482                 {
1483                     // Initialize HP SMR
1484                     cds::gc::HP hp;
1485
1486                     // deal with HP-based data structured
1487                     // ...
1488                 }
1489
1490                 // HP object destroyed
1491                 // Get total post-mortem statistics
1492                 cds::gc::HP::stat const& st = cds::gc::HP::postmortem_statistics();
1493
1494                 printf( "HP statistics:\n"
1495                     "  thread count           = %llu\n"
1496                     "  guard allocated        = %llu\n"
1497                     "  guard freed            = %llu\n"
1498                     "  retired data count     = %llu\n"
1499                     "  free data count        = %llu\n"
1500                     "  scan() call count      = %llu\n"
1501                     "  help_scan() call count = %llu\n",
1502                     st.thread_rec_count,
1503                     st.guard_allocated, st.guard_freed,
1504                     st.retired_count, st.free_count,
1505                     st.scan_count, st.help_scan_count
1506                 );
1507
1508                 cds::Terminate();
1509             }
1510             \endcode
1511         */
1512         static stat const& postmortem_statistics();
1513     };
1514
1515 }} // namespace cds::gc
1516
1517 #endif // #ifndef CDSLIB_GC_HP_SMR_H
1518