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