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