043006cfafaca75028779d9b6023314ddec39c85
[libcds.git] / cds / gc / impl / hp_decl.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_GC_IMPL_HP_DECL_H
4 #define CDSLIB_GC_IMPL_HP_DECL_H
5
6 #include <stdexcept>    // overflow_error
7 #include <cds/gc/details/hp.h>
8 #include <cds/details/marked_ptr.h>
9
10 namespace cds { namespace gc {
11     /// @defgroup cds_garbage_collector Garbage collectors
12
13     /// Hazard Pointer garbage collector
14     /**  @ingroup cds_garbage_collector
15         @headerfile cds/gc/hp.h
16
17         Implementation of classic Hazard Pointer garbage collector.
18
19         Sources:
20             - [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
21             - [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
22             - [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
23
24         Hazard Pointer garbage collector is a singleton. The main user-level part of Hazard Pointer schema is
25         GC class \p %cds::gc::HP and its nested classes. Before use any HP-related class you must initialize HP garbage collector
26         by contructing \p %cds::gc::HP object in beginning of your \p main().
27         See \ref cds_how_to_use "How to use" section for details how to apply garbage collector.
28     */
29     class HP
30     {
31     public:
32         /// Native guarded pointer type
33         /**
34             @headerfile cds/gc/hp.h
35         */
36         typedef gc::hp::hazard_pointer guarded_pointer;
37
38         /// Atomic reference
39         /**
40             @headerfile cds/gc/hp.h
41         */
42         template <typename T> using atomic_ref = atomics::atomic<T *>;
43
44         /// Atomic marked pointer
45         /**
46             @headerfile cds/gc/hp.h
47         */
48         template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
49
50         /// Atomic type
51         /**
52             @headerfile cds/gc/hp.h
53         */
54         template <typename T> using atomic_type = atomics::atomic<T>;
55
56         /// Thread GC implementation for internal usage
57         /**
58             @headerfile cds/gc/hp.h
59         */
60         typedef hp::ThreadGC   thread_gc_impl;
61
62         /// Wrapper for hp::ThreadGC class
63         /**
64             @headerfile cds/gc/hp.h
65             This class performs automatically attaching/detaching Hazard Pointer GC
66             for the current thread.
67         */
68         class thread_gc: public thread_gc_impl
69         {
70             //@cond
71             bool    m_bPersistent;
72             //@endcond
73         public:
74
75             /// Constructor
76             /**
77                 The constructor attaches the current thread to the Hazard Pointer GC
78                 if it is not yet attached.
79                 The \p bPersistent parameter specifies attachment persistence:
80                 - \p true - the class destructor will not detach the thread from Hazard Pointer GC.
81                 - \p false (default) - the class destructor will detach the thread from Hazard Pointer GC.
82             */
83             thread_gc(
84                 bool    bPersistent = false
85             ) ;     //inline in hp_impl.h
86
87             /// Destructor
88             /**
89                 If the object has been created in persistent mode, the destructor does nothing.
90                 Otherwise it detaches the current thread from Hazard Pointer GC.
91             */
92             ~thread_gc() ;  // inline in hp_impl.h
93
94         public: // for internal use only!!!
95             //@cond
96             static cds::gc::hp::details::hp_guard& alloc_guard(); // inline in hp_impl.h
97             static void free_guard( cds::gc::hp::details::hp_guard& g ); // inline in hp_impl.h
98             //@endcond
99         };
100
101         /// Hazard Pointer guard
102         /**
103             @headerfile cds/gc/hp.h
104
105             A guard is the hazard pointer.
106             Additionally, the \p %Guard class manages allocation and deallocation of the hazard pointer
107
108             A \p %Guard object is not copy- and move-constructible
109             and not copy- and move-assignable.
110         */
111         class Guard : public hp::guard
112         {
113             //@cond
114             typedef hp::guard base_class;
115             //@endcond
116
117         public:
118             /// Default ctor
119             Guard()
120             {}
121
122             //@cond
123             Guard( Guard const& ) = delete;
124             Guard( Guard&& s ) = delete;
125             Guard& operator=(Guard const&) = delete;
126             Guard& operator=(Guard&&) = delete;
127             //@endcond
128
129             /// Protects a pointer of type \p atomic<T*>
130             /**
131                 Return the value of \p toGuard
132
133                 The function tries to load \p toGuard and to store it
134                 to the HP slot repeatedly until the guard's value equals \p toGuard
135             */
136             template <typename T>
137             T protect( atomics::atomic<T> const& toGuard )
138             {
139                 T pCur = toGuard.load(atomics::memory_order_relaxed);
140                 T pRet;
141                 do {
142                     pRet = assign( pCur );
143                     pCur = toGuard.load(atomics::memory_order_acquire);
144                 } while ( pRet != pCur );
145                 return pCur;
146             }
147
148             /// Protects a converted pointer of type \p atomic<T*>
149             /**
150                 Return the value of \p toGuard
151
152                 The function tries to load \p toGuard and to store result of \p f functor
153                 to the HP slot repeatedly until the guard's value equals \p toGuard.
154
155                 The function is useful for intrusive containers when \p toGuard is a node pointer
156                 that should be converted to a pointer to the value before protecting.
157                 The parameter \p f of type Func is a functor that makes this conversion:
158                 \code
159                     struct functor {
160                         value_type * operator()( T * p );
161                     };
162                 \endcode
163                 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
164             */
165             template <typename T, class Func>
166             T protect( atomics::atomic<T> const& toGuard, Func f )
167             {
168                 T pCur = toGuard.load(atomics::memory_order_relaxed);
169                 T pRet;
170                 do {
171                     pRet = pCur;
172                     assign( f( pCur ) );
173                     pCur = toGuard.load(atomics::memory_order_acquire);
174                 } while ( pRet != pCur );
175                 return pCur;
176             }
177
178             /// Store \p p to the guard
179             /**
180                 The function equals to a simple assignment the value \p p to guard, no loop is performed.
181                 Can be used for a pointer that cannot be changed concurrently
182             */
183             template <typename T>
184             T * assign( T * p )
185             {
186                 return base_class::operator =(p);
187             }
188
189             //@cond
190             std::nullptr_t assign( std::nullptr_t )
191             {
192                 return base_class::operator =(nullptr);
193             }
194             //@endcond
195
196             /// Copy from \p src guard to \p this guard
197             void copy( Guard const& src )
198             {
199                 assign( src.get_native() );
200             }
201
202             /// Store marked pointer \p p to the guard
203             /**
204                 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
205                 Can be used for a marked pointer that cannot be changed concurrently.
206             */
207             template <typename T, int BITMASK>
208             T * assign( cds::details::marked_ptr<T, BITMASK> p )
209             {
210                 return base_class::operator =( p.ptr() );
211             }
212
213             /// Clear value of the guard
214             void clear()
215             {
216                 assign( nullptr );
217             }
218
219             /// Get the value currently protected
220             template <typename T>
221             T * get() const
222             {
223                 return reinterpret_cast<T *>( get_native() );
224             }
225
226             /// Get native hazard pointer stored
227             guarded_pointer get_native() const
228             {
229                 return base_class::get();
230             }
231         };
232
233         /// Array of Hazard Pointer guards
234         /**
235             @headerfile cds/gc/hp.h
236             The class is intended for allocating an array of hazard pointer guards.
237             Template parameter \p Count defines the size of the array.
238
239             A \p %GuardArray object is not copy- and move-constructible
240             and not copy- and move-assignable.
241         */
242         template <size_t Count>
243         class GuardArray : public hp::array<Count>
244         {
245             //@cond
246             typedef hp::array<Count> base_class;
247             //@endcond
248         public:
249             /// Rebind array for other size \p Count2
250             template <size_t Count2>
251             struct rebind {
252                 typedef GuardArray<Count2>  other   ;   ///< rebinding result
253             };
254
255         public:
256             /// Default ctor
257             GuardArray()
258             {}
259
260             //@cond
261             GuardArray( GuardArray const& ) = delete;
262             GuardArray( GuardArray&& ) = delete;
263             GuardArray& operator=(GuardArray const&) = delete;
264             GuardArray& operator-(GuardArray&&) = delete;
265             //@endcond
266
267             /// Protects a pointer of type \p atomic<T*>
268             /**
269                 Return the value of \p toGuard
270
271                 The function tries to load \p toGuard and to store it
272                 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
273             */
274             template <typename T>
275             T protect( size_t nIndex, atomics::atomic<T> const& toGuard )
276             {
277                 T pRet;
278                 do {
279                     pRet = assign( nIndex, toGuard.load(atomics::memory_order_relaxed) );
280                 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
281
282                 return pRet;
283             }
284
285             /// Protects a pointer of type \p atomic<T*>
286             /**
287                 Return the value of \p toGuard
288
289                 The function tries to load \p toGuard and to store it
290                 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
291
292                 The function is useful for intrusive containers when \p toGuard is a node pointer
293                 that should be converted to a pointer to the value type before guarding.
294                 The parameter \p f of type Func is a functor that makes this conversion:
295                 \code
296                     struct functor {
297                         value_type * operator()( T * p );
298                     };
299                 \endcode
300                 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
301             */
302             template <typename T, class Func>
303             T protect( size_t nIndex, atomics::atomic<T> const& toGuard, Func f )
304             {
305                 T pRet;
306                 do {
307                     assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_relaxed) ));
308                 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
309
310                 return pRet;
311             }
312
313             /// Store \p to the slot \p nIndex
314             /**
315                 The function equals to a simple assignment, no loop is performed.
316             */
317             template <typename T>
318             T * assign( size_t nIndex, T * p )
319             {
320                 base_class::set(nIndex, p);
321                 return p;
322             }
323
324             /// Store marked pointer \p p to the guard
325             /**
326                 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
327                 Can be used for a marked pointer that cannot be changed concurrently.
328             */
329             template <typename T, int BITMASK>
330             T * assign( size_t nIndex, cds::details::marked_ptr<T, BITMASK> p )
331             {
332                 return assign( nIndex, p.ptr() );
333             }
334
335             /// Copy guarded value from \p src guard to slot at index \p nIndex
336             void copy( size_t nIndex, Guard const& src )
337             {
338                 assign( nIndex, src.get_native() );
339             }
340
341             /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
342             void copy( size_t nDestIndex, size_t nSrcIndex )
343             {
344                 assign( nDestIndex, get_native( nSrcIndex ));
345             }
346
347             /// Clear value of the slot \p nIndex
348             void clear( size_t nIndex )
349             {
350                 base_class::clear( nIndex );
351             }
352
353             /// Get current value of slot \p nIndex
354             template <typename T>
355             T * get( size_t nIndex ) const
356             {
357                 return reinterpret_cast<T *>( get_native( nIndex ) );
358             }
359
360             /// Get native hazard pointer stored
361             guarded_pointer get_native( size_t nIndex ) const
362             {
363                 return base_class::operator[](nIndex).get();
364             }
365
366             /// Capacity of the guard array
367             static CDS_CONSTEXPR size_t capacity()
368             {
369                 return Count;
370             }
371         };
372
373         /// Guarded pointer
374         /**
375             A guarded pointer is a pair of a pointer and GC's guard.
376             Usually, it is used for returning a pointer to the item from an lock-free container.
377             The guard prevents the pointer to be early disposed (freed) by GC.
378             After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time.
379
380             Template arguments:
381             - \p GuardedType - a type which the guard stores
382             - \p ValueType - a value type
383             - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
384
385             For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
386             In such case the \p %guarded_ptr is:
387             @code
388             typedef cds::gc::HP::guarded_ptr< foo > intrusive_guarded_ptr;
389             @endcode
390
391             For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
392             For example:
393             @code
394             struct foo {
395                 int const   key;
396                 std::string value;
397             };
398
399             struct value_accessor {
400                 std::string* operator()( foo* pFoo ) const
401                 {
402                     return &(pFoo->value);
403                 }
404             };
405
406             // Guarded ptr
407             typedef cds::gc::HP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
408             @endcode
409
410             You don't need use this class directly.
411             All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
412         */
413         template <typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
414         class guarded_ptr
415         {
416             //@cond
417             struct trivial_cast {
418                 ValueType * operator()( GuardedType * p ) const
419                 {
420                     return p;
421                 }
422             };
423             //@endcond
424
425         public:
426             typedef GuardedType guarded_type; ///< Guarded type
427             typedef ValueType   value_type;   ///< Value type
428
429             /// Functor for casting \p guarded_type to \p value_type
430             typedef typename std::conditional< std::is_same<Cast, void>::value, trivial_cast, Cast >::type value_cast;
431
432             //@cond
433             typedef cds::gc::hp::details::hp_guard native_guard;
434             //@endcond
435
436         private:
437             //@cond
438             native_guard *  m_pGuard;
439             //@endcond
440
441         public:
442             /// Creates empty guarded pointer
443             guarded_ptr() CDS_NOEXCEPT
444                 : m_pGuard(nullptr)
445             {}
446
447             //@cond
448             /// Initializes guarded pointer with \p p
449             explicit guarded_ptr( guarded_type * p ) CDS_NOEXCEPT
450             {
451                 alloc_guard();
452                 assert( m_pGuard );
453                 m_pGuard->set(p);
454             }
455             explicit guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
456                 : m_pGuard( nullptr )
457             {}
458             //@endcond
459
460             /// Move ctor
461             guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
462                 : m_pGuard( gp.m_pGuard )
463             {
464                 gp.m_pGuard = nullptr;
465             }
466
467             /// The guarded pointer is not copy-constructible
468             guarded_ptr( guarded_ptr const& gp ) = delete;
469
470             /// Clears the guarded pointer
471             /**
472                 \ref release is called if guarded pointer is not \ref empty
473             */
474             ~guarded_ptr() CDS_NOEXCEPT
475             {
476                 free_guard();
477             }
478
479             /// Move-assignment operator
480             guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
481             {
482                 // Hazard Pointer array is organized as a stack
483                 if ( m_pGuard && m_pGuard > gp.m_pGuard ) {
484                     m_pGuard->set( gp.m_pGuard->get(atomics::memory_order_relaxed) );
485                     gp.free_guard();
486                 }
487                 else {
488                     free_guard();
489                     m_pGuard = gp.m_pGuard;
490                     gp.m_pGuard = nullptr;
491                 }
492                 return *this;
493             }
494
495             /// The guarded pointer is not copy-assignable
496             guarded_ptr& operator=(guarded_ptr const& gp) = delete;
497
498             /// Returns a pointer to guarded value
499             value_type * operator ->() const CDS_NOEXCEPT
500             {
501                 assert( !empty() );
502                 return value_cast()( reinterpret_cast<guarded_type *>(m_pGuard->get()));
503             }
504
505             /// Returns a reference to guarded value
506             value_type& operator *() CDS_NOEXCEPT
507             {
508                 assert( !empty());
509                 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
510             }
511
512             /// Returns const reference to guarded value
513             value_type const& operator *() const CDS_NOEXCEPT
514             {
515                 assert( !empty() );
516                 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
517             }
518
519             /// Checks if the guarded pointer is \p nullptr
520             bool empty() const CDS_NOEXCEPT
521             {
522                 return !m_pGuard || m_pGuard->get( atomics::memory_order_relaxed ) == nullptr;
523             }
524
525             /// \p bool operator returns <tt>!empty()</tt>
526             explicit operator bool() const CDS_NOEXCEPT
527             {
528                 return !empty();
529             }
530
531             /// Clears guarded pointer
532             /**
533                 If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
534                 Dereferncing the guarded pointer after \p release() is dangerous.
535             */
536             void release() CDS_NOEXCEPT
537             {
538                 free_guard();
539             }
540
541             //@cond
542             // For internal use only!!!
543             native_guard& guard() CDS_NOEXCEPT
544             {
545                 alloc_guard();
546                 assert( m_pGuard );
547                 return *m_pGuard;
548             }
549             //@endcond
550
551         private:
552             //@cond
553             void alloc_guard()
554             {
555                 if ( !m_pGuard )
556                     m_pGuard = &thread_gc::alloc_guard();
557             }
558
559             void free_guard()
560             {
561                 if ( m_pGuard ) {
562                     thread_gc::free_guard( *m_pGuard );
563                     m_pGuard = nullptr;
564                 }
565             }
566             //@endcond
567         };
568
569     public:
570         /// \p scan() type
571         enum class scan_type {
572             classic = hp::classic,    ///< classic scan as described in Michael's papers
573             inplace = hp::inplace     ///< inplace scan without allocation
574         };
575         /// Initializes %HP singleton
576         /**
577             The constructor initializes GC singleton with passed parameters.
578             If GC instance is not exist then the function creates the instance.
579             Otherwise it does nothing.
580
581             The Michael's %HP reclamation schema depends of three parameters:
582             - \p nHazardPtrCount - hazard pointer count per thread. Usually it is small number (up to 10) depending from
583                 the data structure algorithms. By default, if \p nHazardPtrCount = 0, the function
584                 uses maximum of the hazard pointer count for CDS library.
585             - \p nMaxThreadCount - max count of thread with using Hazard Pointer GC in your application. Default is 100.
586             - \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
587                 <tt> nHazardPtrCount * nMaxThreadCount </tt>. Default is <tt>2 * nHazardPtrCount * nMaxThreadCount </tt>.
588         */
589         HP(
590             size_t nHazardPtrCount = 0,     ///< Hazard pointer count per thread
591             size_t nMaxThreadCount = 0,     ///< Max count of simultaneous working thread in your application
592             size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
593             scan_type nScanType = scan_type::inplace   ///< Scan type (see \p scan_type enum)
594         )
595         {
596             hp::GarbageCollector::Construct(
597                 nHazardPtrCount,
598                 nMaxThreadCount,
599                 nMaxRetiredPtrCount,
600                 static_cast<hp::scan_type>(nScanType)
601             );
602         }
603
604         /// Terminates GC singleton
605         /**
606             The destructor destroys %HP global object. After calling of this function you may \b NOT
607             use CDS data structures based on \p %cds::gc::HP. 
608             Usually, %HP object is destroyed at the end of your \p main().
609         */
610         ~HP()
611         {
612             hp::GarbageCollector::Destruct( true );
613         }
614
615         /// Checks if count of hazard pointer is no less than \p nCountNeeded
616         /**
617             If \p bRaiseException is \p true (that is the default), the function raises
618             an \p std::overflow_error exception "Too few hazard pointers"
619             if \p nCountNeeded is more than the count of hazard pointer per thread.
620         */
621         static bool check_available_guards( size_t nCountNeeded, bool bRaiseException = true )
622         {
623             if ( hp::GarbageCollector::instance().getHazardPointerCount() < nCountNeeded ) {
624                 if ( bRaiseException )
625                     throw std::overflow_error( "Too few hazard pointers" );
626                 return false;
627             }
628             return true;
629         }
630
631         /// Returns max Hazard Pointer count
632         static size_t max_hazard_count()
633         {
634             return hp::GarbageCollector::instance().getHazardPointerCount();
635         }
636
637         /// Returns max count of thread
638         static size_t max_thread_count()
639         {
640             return hp::GarbageCollector::instance().getMaxThreadCount();
641         }
642
643         /// Returns capacity of retired pointer array
644         static size_t retired_array_capacity()
645         {
646             return hp::GarbageCollector::instance().getMaxRetiredPtrCount();
647         }
648
649         /// Retire pointer \p p with function \p pFunc
650         /**
651             The function places pointer \p p to array of pointers ready for removing.
652             (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
653             Deleting the pointer is the function \p pFunc call.
654         */
655         template <typename T>
656         static void retire( T * p, void (* pFunc)(T *) );   // inline in hp_impl.h
657
658         /// Retire pointer \p p with functor of type \p Disposer
659         /**
660             The function places pointer \p p to array of pointers ready for removing.
661             (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
662
663             Deleting the pointer is an invocation of some object of type \p Disposer; the interface of \p Disposer is:
664             \code
665             template <typename T>
666             struct disposer {
667                 void operator()( T * p )    ;   // disposing operator
668             };
669             \endcode
670             Since the functor call can happen at any time after \p retire call, additional restrictions are imposed to \p Disposer type:
671             - it should be stateless functor
672             - it should be default-constructible
673             - the result of functor call with argument \p p should not depend on where the functor will be called.
674
675             \par Examples:
676             Operator \p delete functor:
677             \code
678             template <typename T>
679             struct disposer {
680                 void operator ()( T * p ) {
681                     delete p;
682                 }
683             };
684
685             // How to call GC::retire method
686             int * p = new int;
687
688             // ... use p in lock-free manner
689
690             cds::gc::HP::retire<disposer>( p ) ;   // place p to retired pointer array of HP GC
691             \endcode
692
693             Functor based on \p std::allocator :
694             \code
695             template <typename ALLOC = std::allocator<int> >
696             struct disposer {
697                 template <typename T>
698                 void operator()( T * p ) {
699                     typedef typename ALLOC::templare rebind<T>::other   alloc_t;
700                     alloc_t a;
701                     a.destroy( p );
702                     a.deallocate( p, 1 );
703                 }
704             };
705             \endcode
706         */
707         template <class Disposer, typename T>
708         static void retire( T * p );   // inline in hp_impl.h
709
710         /// Get current scan strategy
711         static scan_type getScanType()
712         {
713             return static_cast<scan_type>( hp::GarbageCollector::instance().getScanType());
714         }
715
716         /// Set current scan strategy
717         static void setScanType(
718             scan_type nScanType     ///< new scan strategy
719         )
720         {
721             hp::GarbageCollector::instance().setScanType( static_cast<hp::scan_type>(nScanType) );
722         }
723
724         /// Checks if Hazard Pointer GC is constructed and may be used
725         static bool isUsed()
726         {
727             return hp::GarbageCollector::isUsed();
728         }
729
730         /// Forced GC cycle call for current thread
731         /**
732             Usually, this function should not be called directly.
733         */
734         static void scan()  ;   // inline in hp_impl.h
735
736         /// Synonym for \ref scan()
737         static void force_dispose()
738         {
739             scan();
740         }
741     };
742 }}  // namespace cds::gc
743
744 #endif  // #ifndef CDSLIB_GC_IMPL_HP_DECL_H