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