bugfix in cds::gc::HP::guarded_ptr
[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             explicit guarded_ptr( guarded_type * p ) CDS_NOEXCEPT
448             {
449                 alloc_guard();
450                 assert( m_pGuard );
451                 m_pGuard->set(p);
452             }
453             explicit 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                 // Hazard Pointer array is organized as a stack
481                 if ( m_pGuard && m_pGuard > gp.m_pGuard ) {
482                     m_pGuard->set( gp.m_pGuard->get(atomics::memory_order_relaxed) );
483                     gp.free_guard();
484                 }
485                 else {
486                     free_guard();
487                     m_pGuard = gp.m_pGuard;
488                     gp.m_pGuard = nullptr;
489                 }
490                 return *this;
491             }
492
493             /// The guarded pointer is not copy-assignable
494             guarded_ptr& operator=(guarded_ptr const& gp) = delete;
495
496             /// Returns a pointer to guarded value
497             value_type * operator ->() const CDS_NOEXCEPT
498             {
499                 assert( !empty() );
500                 return value_cast()( reinterpret_cast<guarded_type *>(m_pGuard->get()));
501             }
502
503             /// Returns a reference to guarded value
504             value_type& operator *() CDS_NOEXCEPT
505             {
506                 assert( !empty());
507                 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
508             }
509
510             /// Returns const reference to guarded value
511             value_type const& operator *() const CDS_NOEXCEPT
512             {
513                 assert( !empty() );
514                 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
515             }
516
517             /// Checks if the guarded pointer is \p nullptr
518             bool empty() const CDS_NOEXCEPT
519             {
520                 return !m_pGuard || m_pGuard->get( atomics::memory_order_relaxed ) == nullptr;
521             }
522
523             /// \p bool operator returns <tt>!empty()</tt>
524             explicit operator bool() const CDS_NOEXCEPT
525             {
526                 return !empty();
527             }
528
529             /// Clears guarded pointer
530             /**
531                 If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
532                 Dereferncing the guarded pointer after \p release() is dangerous.
533             */
534             void release() CDS_NOEXCEPT
535             {
536                 if ( m_pGuard )
537                     m_pGuard->clear();
538             }
539
540             //@cond
541             // For internal use only!!!
542             native_guard& guard() CDS_NOEXCEPT
543             {
544                 alloc_guard();
545                 assert( m_pGuard );
546                 return *m_pGuard;
547             }
548             //@endcond
549
550         private:
551             //@cond
552             void alloc_guard()
553             {
554                 if ( !m_pGuard )
555                     m_pGuard = &thread_gc::alloc_guard();
556             }
557
558             void free_guard()
559             {
560                 if ( m_pGuard ) {
561                     thread_gc::free_guard( *m_pGuard );
562                     m_pGuard = nullptr;
563                 }
564             }
565             //@endcond
566         };
567
568     public:
569         /// \p scan() type
570         enum class scan_type {
571             classic = hp::classic,    ///< classic scan as described in Michael's papers
572             inplace = hp::inplace     ///< inplace scan without allocation
573         };
574         /// Initializes hp::GarbageCollector singleton
575         /**
576             The constructor initializes GC singleton with passed parameters.
577             If GC instance is not exist then the function creates the instance.
578             Otherwise it does nothing.
579
580             The Michael's HP reclamation schema depends of three parameters:
581             - \p nHazardPtrCount - hazard pointer count per thread. Usually it is small number (up to 10) depending from
582                 the data structure algorithms. By default, if \p nHazardPtrCount = 0, the function
583                 uses maximum of the hazard pointer count for CDS library.
584             - \p nMaxThreadCount - max count of thread with using Hazard Pointer GC in your application. Default is 100.
585             - \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
586                 <tt> nHazardPtrCount * nMaxThreadCount </tt>. Default is <tt>2 * nHazardPtrCount * nMaxThreadCount </tt>.
587         */
588         HP(
589             size_t nHazardPtrCount = 0,     ///< Hazard pointer count per thread
590             size_t nMaxThreadCount = 0,     ///< Max count of simultaneous working thread in your application
591             size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
592             scan_type nScanType = scan_type::inplace   ///< Scan type (see \p scan_type enum)
593         )
594         {
595             hp::GarbageCollector::Construct(
596                 nHazardPtrCount,
597                 nMaxThreadCount,
598                 nMaxRetiredPtrCount,
599                 static_cast<hp::scan_type>(nScanType)
600             );
601         }
602
603         /// Terminates GC singleton
604         /**
605             The destructor calls \code hp::GarbageCollector::Destruct( true ) \endcode
606         */
607         ~HP()
608         {
609             hp::GarbageCollector::Destruct( true );
610         }
611
612         /// Checks if count of hazard pointer is no less than \p nCountNeeded
613         /**
614             If \p bRaiseException is \p true (that is the default), the function raises 
615             an \p std::overflow_error exception "Too few hazard pointers"
616             if \p nCountNeeded is more than the count of hazard pointer per thread.
617         */
618         static bool check_available_guards( size_t nCountNeeded, bool bRaiseException = true )
619         {
620             if ( hp::GarbageCollector::instance().getHazardPointerCount() < nCountNeeded ) {
621                 if ( bRaiseException )
622                     throw std::overflow_error( "Too few hazard pointers" );
623                 return false;
624             }
625             return true;
626         }
627
628         /// Returns max Hazard Pointer count
629         static size_t max_hazard_count()
630         {
631             return hp::GarbageCollector::instance().getHazardPointerCount();
632         }
633
634         /// Returns max count of thread
635         static size_t max_thread_count()
636         {
637             return hp::GarbageCollector::instance().getMaxThreadCount();
638         }
639
640         /// Returns capacity of retired pointer array
641         static size_t retired_array_capacity()
642         {
643             return hp::GarbageCollector::instance().getMaxRetiredPtrCount();
644         }
645
646         /// Retire pointer \p p with function \p pFunc
647         /**
648             The function places pointer \p p to array of pointers ready for removing.
649             (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
650             Deleting the pointer is the function \p pFunc call.
651         */
652         template <typename T>
653         static void retire( T * p, void (* pFunc)(T *) );   // inline in hp_impl.h
654
655         /// Retire pointer \p p with functor of type \p Disposer
656         /**
657             The function places pointer \p p to array of pointers ready for removing.
658             (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
659
660             Deleting the pointer is an invocation of some object of type \p Disposer; the interface of \p Disposer is:
661             \code
662             template <typename T>
663             struct disposer {
664                 void operator()( T * p )    ;   // disposing operator
665             };
666             \endcode
667             Since the functor call can happen at any time after \p retire call, additional restrictions are imposed to \p Disposer type:
668             - it should be stateless functor
669             - it should be default-constructible
670             - the result of functor call with argument \p p should not depend on where the functor will be called.
671
672             \par Examples:
673             Operator \p delete functor:
674             \code
675             template <typename T>
676             struct disposer {
677                 void operator ()( T * p ) {
678                     delete p;
679                 }
680             };
681
682             // How to call GC::retire method
683             int * p = new int;
684
685             // ... use p in lock-free manner
686
687             cds::gc::HP::retire<disposer>( p ) ;   // place p to retired pointer array of HP GC
688             \endcode
689
690             Functor based on \p std::allocator :
691             \code
692             template <typename ALLOC = std::allocator<int> >
693             struct disposer {
694                 template <typename T>
695                 void operator()( T * p ) {
696                     typedef typename ALLOC::templare rebind<T>::other   alloc_t;
697                     alloc_t a;
698                     a.destroy( p );
699                     a.deallocate( p, 1 );
700                 }
701             };
702             \endcode
703         */
704         template <class Disposer, typename T>
705         static void retire( T * p );   // inline in hp_impl.h
706
707         /// Get current scan strategy
708         static scan_type getScanType()
709         {
710             return static_cast<scan_type>( hp::GarbageCollector::instance().getScanType());
711         }
712
713         /// Set current scan strategy
714         static void setScanType(
715             scan_type nScanType     ///< new scan strategy
716         )
717         {
718             hp::GarbageCollector::instance().setScanType( static_cast<hp::scan_type>(nScanType) );
719         }
720
721         /// Checks if Hazard Pointer GC is constructed and may be used
722         static bool isUsed()
723         {
724             return hp::GarbageCollector::isUsed();
725         }
726
727         /// Forced GC cycle call for current thread
728         /**
729             Usually, this function should not be called directly.
730         */
731         static void scan()  ;   // inline in hp_impl.h
732
733         /// Synonym for \ref scan()
734         static void force_dispose()
735         {
736             scan();
737         }
738     };
739 }}  // namespace cds::gc
740
741 #endif  // #ifndef __CDS_GC_IMPL_HP_DECL_H