2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
6 Source code repo: http://github.com/khizmax/libcds/
7 Download: http://sourceforge.net/projects/libcds/files/
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
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.
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.
31 #ifndef CDSLIB_GC_IMPL_DHP_DECL_H
32 #define CDSLIB_GC_IMPL_DHP_DECL_H
34 #include <cds/gc/details/dhp.h>
35 #include <cds/details/marked_ptr.h>
36 #include <cds/details/static_functor.h>
38 namespace cds { namespace gc {
40 /// Dynamic Hazard Pointer garbage collector
41 /** @ingroup cds_garbage_collector
42 @headerfile cds/gc/dhp.h
44 Implementation of Dynamic Hazard Pointer garbage collector.
47 - [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
48 - [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
49 - [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
51 Dynamic Hazard Pointers SMR (safe memory reclamation) provides an unbounded number of hazard pointer per thread
52 despite of classic Hazard Pointer SMR in which the count of the hazard pointef per thread is limited.
54 See \ref cds_how_to_use "How to use" section for details how to apply garbage collector.
59 /// Native guarded pointer type
61 @headerfile cds/gc/dhp.h
63 typedef void * guarded_pointer;
67 @headerfile cds/gc/dhp.h
69 template <typename T> using atomic_ref = atomics::atomic<T *>;
73 @headerfile cds/gc/dhp.h
75 template <typename T> using atomic_type = atomics::atomic<T>;
77 /// Atomic marked pointer
79 @headerfile cds/gc/dhp.h
81 template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
83 /// Thread GC implementation for internal usage
85 @headerfile cds/gc/dhp.h
87 typedef dhp::ThreadGC thread_gc_impl;
89 /// Thread-level garbage collector
91 @headerfile cds/gc/dhp.h
92 This class performs automatically attaching/detaching Dynamic Hazard Pointer GC
93 for the current thread.
95 class thread_gc: public thread_gc_impl
103 The constructor attaches the current thread to the Dynamic Hazard Pointer GC
104 if it is not yet attached.
105 The \p bPersistent parameter specifies attachment persistence:
106 - \p true - the class destructor will not detach the thread from Dynamic Hazard Pointer GC.
107 - \p false (default) - the class destructor will detach the thread from Dynamic Hazard Pointer GC.
110 bool bPersistent = false
111 ) ; // inline in dhp_impl.h
115 If the object has been created in persistent mode, the destructor does nothing.
116 Otherwise it detaches the current thread from Dynamic Hazard Pointer GC.
118 ~thread_gc() ; // inline in dhp_impl.h
120 public: // for internal use only!!!
122 static void alloc_guard( cds::gc::dhp::details::guard& g ); // inline in dhp_impl.h
123 static void free_guard( cds::gc::dhp::details::guard& g ); // inline in dhp_impl.h
128 /// Dynamic Hazard Pointer guard
130 @headerfile cds/gc/dhp.h
132 A guard is the hazard pointer.
133 Additionally, the \p %Guard class manages allocation and deallocation of the hazard pointer
135 A \p %Guard object is not copy- and move-constructible
136 and not copy- and move-assignable.
138 class Guard: public dhp::Guard
141 typedef dhp::Guard base_class;
144 public: // for internal use only
146 typedef cds::gc::dhp::details::guard native_guard;
155 Guard( Guard const& ) = delete;
156 Guard( Guard&& s ) = delete;
157 Guard& operator=(Guard const&) = delete;
158 Guard& operator=(Guard&&) = delete;
161 /// Protects a pointer of type <tt> atomic<T*> </tt>
163 Return the value of \p toGuard
165 The function tries to load \p toGuard and to store it
166 to the HP slot repeatedly until the guard's value equals \p toGuard
168 template <typename T>
169 T protect( atomics::atomic<T> const& toGuard )
171 T pCur = toGuard.load(atomics::memory_order_acquire);
174 pRet = assign( pCur );
175 pCur = toGuard.load(atomics::memory_order_acquire);
176 } while ( pRet != pCur );
180 /// Protects a converted pointer of type <tt> atomic<T*> </tt>
182 Return the value of \p toGuard
184 The function tries to load \p toGuard and to store result of \p f functor
185 to the HP slot repeatedly until the guard's value equals \p toGuard.
187 The function is useful for intrusive containers when \p toGuard is a node pointer
188 that should be converted to a pointer to the value type before guarding.
189 The parameter \p f of type Func is a functor that makes this conversion:
192 value_type * operator()( T * p );
195 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
197 template <typename T, class Func>
198 T protect( atomics::atomic<T> const& toGuard, Func f )
200 T pCur = toGuard.load(atomics::memory_order_acquire);
205 pCur = toGuard.load(atomics::memory_order_acquire);
206 } while ( pRet != pCur );
210 /// Store \p p to the guard
212 The function is just an assignment, no loop is performed.
213 Can be used for a pointer that cannot be changed concurrently
214 or for already guarded pointer.
216 template <typename T>
219 return base_class::operator =(p);
223 std::nullptr_t assign( std::nullptr_t )
225 return base_class::operator =(nullptr);
229 /// Store marked pointer \p p to the guard
231 The function is just an assignment of <tt>p.ptr()</tt>, no loop is performed.
232 Can be used for a marked pointer that cannot be changed concurrently
233 or for already guarded pointer.
235 template <typename T, int BITMASK>
236 T * assign( cds::details::marked_ptr<T, BITMASK> p )
238 return base_class::operator =( p.ptr() );
241 /// Copy from \p src guard to \p this guard
242 void copy( Guard const& src )
244 assign( src.get_native() );
247 /// Clears value of the guard
253 /// Gets the value currently protected (relaxed read)
254 template <typename T>
257 return reinterpret_cast<T *>( get_native() );
260 /// Gets native guarded pointer stored
261 guarded_pointer get_native() const
263 return base_class::get_guard()->pPost.load(atomics::memory_order_relaxed);
267 /// Array of Dynamic Hazard Pointer guards
269 @headerfile cds/gc/dhp.h
270 The class is intended for allocating an array of hazard pointer guards.
271 Template parameter \p Count defines the size of the array.
273 A \p %GuardArray object is not copy- and move-constructible
274 and not copy- and move-assignable.
276 template <size_t Count>
277 class GuardArray: public dhp::GuardArray<Count>
280 typedef dhp::GuardArray<Count> base_class;
283 /// Rebind array for other size \p OtherCount
284 template <size_t OtherCount>
286 typedef GuardArray<OtherCount> other ; ///< rebinding result
295 GuardArray( GuardArray const& ) = delete;
296 GuardArray( GuardArray&& ) = delete;
297 GuardArray& operator=(GuardArray const&) = delete;
298 GuardArray& operator-(GuardArray&&) = delete;
301 /// Protects a pointer of type \p atomic<T*>
303 Return the value of \p toGuard
305 The function tries to load \p toGuard and to store it
306 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
308 template <typename T>
309 T protect( size_t nIndex, atomics::atomic<T> const& toGuard )
313 pRet = assign( nIndex, toGuard.load(atomics::memory_order_acquire) );
314 } while ( pRet != toGuard.load(atomics::memory_order_relaxed));
319 /// Protects a pointer of type \p atomic<T*>
321 Return the value of \p toGuard
323 The function tries to load \p toGuard and to store it
324 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
326 The function is useful for intrusive containers when \p toGuard is a node pointer
327 that should be converted to a pointer to the value type before guarding.
328 The parameter \p f of type Func is a functor to make that conversion:
331 value_type * operator()( T * p );
334 Actually, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
336 template <typename T, class Func>
337 T protect( size_t nIndex, atomics::atomic<T> const& toGuard, Func f )
341 assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_acquire) ));
342 } while ( pRet != toGuard.load(atomics::memory_order_relaxed));
347 /// Store \p p to the slot \p nIndex
349 The function is just an assignment, no loop is performed.
351 template <typename T>
352 T * assign( size_t nIndex, T * p )
354 base_class::set(nIndex, p);
358 /// Store marked pointer \p p to the guard
360 The function is just an assignment of <tt>p.ptr()</tt>, no loop is performed.
361 Can be used for a marked pointer that cannot be changed concurrently
362 or for already guarded pointer.
364 template <typename T, int Bitmask>
365 T * assign( size_t nIndex, cds::details::marked_ptr<T, Bitmask> p )
367 return assign( nIndex, p.ptr() );
370 /// Copy guarded value from \p src guard to slot at index \p nIndex
371 void copy( size_t nIndex, Guard const& src )
373 assign( nIndex, src.get_native() );
376 /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
377 void copy( size_t nDestIndex, size_t nSrcIndex )
379 assign( nDestIndex, get_native( nSrcIndex ));
382 /// Clear value of the slot \p nIndex
383 void clear( size_t nIndex )
385 base_class::clear( nIndex );
388 /// Get current value of slot \p nIndex
389 template <typename T>
390 T * get( size_t nIndex ) const
392 return reinterpret_cast<T *>( get_native( nIndex ) );
395 /// Get native guarded pointer stored
396 guarded_pointer get_native( size_t nIndex ) const
398 return base_class::operator[](nIndex).get_guard()->pPost.load(atomics::memory_order_relaxed);
401 /// Capacity of the guard array
402 static CDS_CONSTEXPR size_t capacity()
410 A guarded pointer is a pair of a pointer and GC's guard.
411 Usually, it is used for returning a pointer to the item from an lock-free container.
412 The guard prevents the pointer to be early disposed (freed) by GC.
413 After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time.
416 - \p GuardedType - a type which the guard stores
417 - \p ValueType - a value type
418 - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
420 For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
421 In such case the \p %guarded_ptr is:
423 typedef cds::gc::DHP::guarded_ptr< foo > intrusive_guarded_ptr;
426 For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
434 struct value_accessor {
435 std::string* operator()( foo* pFoo ) const
437 return &(pFoo->value);
442 typedef cds::gc::DHP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
445 You don't need use this class directly.
446 All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
448 template <typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
452 struct trivial_cast {
453 ValueType * operator()( GuardedType * p ) const
461 typedef GuardedType guarded_type; ///< Guarded type
462 typedef ValueType value_type; ///< Value type
464 /// Functor for casting \p guarded_type to \p value_type
465 typedef typename std::conditional< std::is_same<Cast, void>::value, trivial_cast, Cast >::type value_cast;
468 typedef cds::gc::dhp::details::guard native_guard;
473 native_guard m_guard;
477 /// Creates empty guarded pointer
478 guarded_ptr() CDS_NOEXCEPT
482 /// Initializes guarded pointer with \p p
483 explicit guarded_ptr( guarded_type * p ) CDS_NOEXCEPT
486 assert( m_guard.is_initialized() );
489 explicit guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
494 guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
496 m_guard.set_guard( gp.m_guard.release_guard() );
499 /// The guarded pointer is not copy-constructible
500 guarded_ptr( guarded_ptr const& gp ) = delete;
502 /// Clears the guarded pointer
504 \ref release is called if guarded pointer is not \ref empty
506 ~guarded_ptr() CDS_NOEXCEPT
511 /// Move-assignment operator
512 guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
515 m_guard.set_guard( gp.m_guard.release_guard() );
519 /// The guarded pointer is not copy-assignable
520 guarded_ptr& operator=(guarded_ptr const& gp) = delete;
522 /// Returns a pointer to guarded value
523 value_type * operator ->() const CDS_NOEXCEPT
526 return value_cast()( reinterpret_cast<guarded_type *>(m_guard.get()));
529 /// Returns a reference to guarded value
530 value_type& operator *() CDS_NOEXCEPT
533 return *value_cast()(reinterpret_cast<guarded_type *>(m_guard.get()));
536 /// Returns const reference to guarded value
537 value_type const& operator *() const CDS_NOEXCEPT
540 return *value_cast()(reinterpret_cast<guarded_type *>(m_guard.get()));
543 /// Checks if the guarded pointer is \p nullptr
544 bool empty() const CDS_NOEXCEPT
546 return !m_guard.is_initialized() || m_guard.get( atomics::memory_order_relaxed ) == nullptr;
549 /// \p bool operator returns <tt>!empty()</tt>
550 explicit operator bool() const CDS_NOEXCEPT
555 /// Clears guarded pointer
557 If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
558 Dereferncing the guarded pointer after \p release() is dangerous.
560 void release() CDS_NOEXCEPT
566 // For internal use only!!!
567 native_guard& guard() CDS_NOEXCEPT
570 assert( m_guard.is_initialized() );
574 void reset(guarded_type * p) CDS_NOEXCEPT
577 assert( m_guard.is_initialized() );
587 if ( !m_guard.is_initialized() )
588 thread_gc::alloc_guard( m_guard );
593 if ( m_guard.is_initialized() )
594 thread_gc::free_guard( m_guard );
600 /// Initializes %DHP memory manager singleton
602 Constructor creates and initializes %DHP global object.
603 %DHP object should be created before using CDS data structure based on \p %cds::gc::DHP GC. Usually,
604 it is created in the \p main() function.
605 After creating of global object you may use CDS data structures based on \p %cds::gc::DHP.
608 - \p nLiberateThreshold - \p scan() threshold. When count of retired pointers reaches this value,
609 the \p scan() member function would be called for freeing retired pointers.
610 - \p nInitialThreadGuardCount - initial count of guard allocated for each thread.
611 When a thread is initialized the GC allocates local guard pool for the thread from common guard pool.
612 By perforce the local thread's guard pool is grown automatically from common pool.
613 When the thread terminated its guard pool is backed to common GC's pool.
614 - \p nEpochCount: internally, DHP memory manager uses epoch-based schema to solve
615 ABA problem for internal data. \p nEpochCount specifies the epoch count,
616 i.e. the count of simultaneously working threads that remove the elements
617 of DHP-based concurrent data structure. Default value is 16.
620 size_t nLiberateThreshold = 1024
621 , size_t nInitialThreadGuardCount = 8
622 , size_t nEpochCount = 16
625 dhp::GarbageCollector::Construct( nLiberateThreshold, nInitialThreadGuardCount, nEpochCount );
628 /// Destroys %DHP memory manager
630 The destructor destroys %DHP global object. After calling of this function you may \b NOT
631 use CDS data structures based on \p %cds::gc::DHP.
632 Usually, %DHP object is destroyed at the end of your \p main().
636 dhp::GarbageCollector::Destruct();
639 /// Checks if count of hazard pointer is no less than \p nCountNeeded
641 The function always returns \p true since the guard count is unlimited for
642 \p %gc::DHP garbage collector.
644 static CDS_CONSTEXPR bool check_available_guards(
645 #ifdef CDS_DOXYGEN_INVOKED
650 bool /*bRaiseException*/ = true )
655 /// Retire pointer \p p with function \p pFunc
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 guarded pointer points to it.
659 Deleting the pointer is the function \p pFunc call.
661 template <typename T>
662 static void retire( T * p, void (* pFunc)(T *) )
664 dhp::GarbageCollector::instance().retirePtr( p, pFunc );
667 /// Retire pointer \p p with functor of type \p Disposer
669 The function places pointer \p p to array of pointers ready for removing.
670 (so called retired pointer array). The pointer can be safely removed when no guarded pointer points to it.
672 See \p gc::HP::retire for \p Disposer requirements.
674 template <class Disposer, typename T>
675 static void retire( T * p )
677 retire( p, cds::details::static_functor<Disposer, T>::call );
680 /// Checks if Dynamic Hazard Pointer GC is constructed and may be used
683 return dhp::GarbageCollector::isUsed();
686 /// Forced GC cycle call for current thread
688 Usually, this function should not be called directly.
690 static void scan() ; // inline in dhp_impl.h
692 /// Synonym for \ref scan()
693 static void force_dispose()
699 }} // namespace cds::gc
701 #endif // #ifndef CDSLIB_GC_IMPL_DHP_DECL_H