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