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_HP_DECL_H
32 #define CDSLIB_GC_IMPL_HP_DECL_H
34 #include <stdexcept> // overflow_error
35 #include <cds/gc/details/hp.h>
36 #include <cds/details/marked_ptr.h>
38 namespace cds { namespace gc {
39 /// @defgroup cds_garbage_collector Garbage collectors
41 /// Hazard Pointer garbage collector
42 /** @ingroup cds_garbage_collector
43 @headerfile cds/gc/hp.h
45 Implementation of classic Hazard Pointer garbage collector.
48 - [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
49 - [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
50 - [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
52 Hazard Pointer garbage collector is a singleton. The main user-level part of Hazard Pointer schema is
53 GC class \p %cds::gc::HP and its nested classes. Before use any HP-related class you must initialize HP garbage collector
54 by contructing \p %cds::gc::HP object in beginning of your \p main().
55 See \ref cds_how_to_use "How to use" section for details how to apply garbage collector.
60 /// Native guarded pointer type
62 @headerfile cds/gc/hp.h
64 typedef gc::hp::hazard_pointer guarded_pointer;
68 @headerfile cds/gc/hp.h
70 template <typename T> using atomic_ref = atomics::atomic<T *>;
72 /// Atomic marked pointer
74 @headerfile cds/gc/hp.h
76 template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
80 @headerfile cds/gc/hp.h
82 template <typename T> using atomic_type = atomics::atomic<T>;
84 /// Thread GC implementation for internal usage
86 @headerfile cds/gc/hp.h
88 typedef hp::ThreadGC thread_gc_impl;
90 /// Wrapper for hp::ThreadGC class
92 @headerfile cds/gc/hp.h
93 This class performs automatically attaching/detaching Hazard Pointer GC
94 for the current thread.
96 class thread_gc: public thread_gc_impl
105 The constructor attaches the current thread to the Hazard Pointer GC
106 if it is not yet attached.
107 The \p bPersistent parameter specifies attachment persistence:
108 - \p true - the class destructor will not detach the thread from Hazard Pointer GC.
109 - \p false (default) - the class destructor will detach the thread from Hazard Pointer GC.
112 bool bPersistent = false
113 ) ; //inline in hp_impl.h
117 If the object has been created in persistent mode, the destructor does nothing.
118 Otherwise it detaches the current thread from Hazard Pointer GC.
120 ~thread_gc() ; // inline in hp_impl.h
122 public: // for internal use only!!!
124 static cds::gc::hp::details::hp_guard& alloc_guard(); // inline in hp_impl.h
125 static void free_guard( cds::gc::hp::details::hp_guard& g ); // inline in hp_impl.h
129 /// Hazard Pointer guard
131 @headerfile cds/gc/hp.h
133 A guard is the hazard pointer.
134 Additionally, the \p %Guard class manages allocation and deallocation of the hazard pointer
136 A \p %Guard object is not copy- and move-constructible
137 and not copy- and move-assignable.
139 class Guard : public hp::guard
142 typedef hp::guard base_class;
151 Guard( Guard const& ) = delete;
152 Guard( Guard&& s ) = delete;
153 Guard& operator=(Guard const&) = delete;
154 Guard& operator=(Guard&&) = delete;
157 /// Protects a pointer of type \p atomic<T*>
159 Return the value of \p toGuard
161 The function tries to load \p toGuard and to store it
162 to the HP slot repeatedly until the guard's value equals \p toGuard
164 template <typename T>
165 T protect( atomics::atomic<T> const& toGuard )
167 T pCur = toGuard.load(atomics::memory_order_acquire);
170 pRet = assign( pCur );
171 pCur = toGuard.load(atomics::memory_order_acquire);
172 } while ( pRet != pCur );
176 /// Protects a converted pointer of type \p atomic<T*>
178 Return the value of \p toGuard
180 The function tries to load \p toGuard and to store result of \p f functor
181 to the HP slot repeatedly until the guard's value equals \p toGuard.
183 The function is useful for intrusive containers when \p toGuard is a node pointer
184 that should be converted to a pointer to the value before protecting.
185 The parameter \p f of type Func is a functor that makes this conversion:
188 value_type * operator()( T * p );
191 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
193 template <typename T, class Func>
194 T protect( atomics::atomic<T> const& toGuard, Func f )
196 T pCur = toGuard.load(atomics::memory_order_acquire);
201 pCur = toGuard.load(atomics::memory_order_acquire);
202 } while ( pRet != pCur );
206 /// Store \p p to the guard
208 The function equals to a simple assignment the value \p p to guard, no loop is performed.
209 Can be used for a pointer that cannot be changed concurrently
211 template <typename T>
212 T * assign( T * p ); // inline in hp_impl.h
215 std::nullptr_t assign( std::nullptr_t )
217 return base_class::operator =(nullptr);
221 /// Copy from \p src guard to \p this guard
222 void copy( Guard const& src )
224 assign( src.get_native() );
227 /// Store marked pointer \p p to the guard
229 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
230 Can be used for a marked pointer that cannot be changed concurrently.
232 template <typename T, int BITMASK>
233 T * assign( cds::details::marked_ptr<T, BITMASK> p )
235 return base_class::operator =( p.ptr() );
238 /// Clear value of the guard
244 /// Get the value currently protected
245 template <typename T>
248 return reinterpret_cast<T *>( get_native() );
251 /// Get native hazard pointer stored
252 guarded_pointer get_native() const
254 return base_class::get();
258 /// Array of Hazard Pointer guards
260 @headerfile cds/gc/hp.h
261 The class is intended for allocating an array of hazard pointer guards.
262 Template parameter \p Count defines the size of the array.
264 A \p %GuardArray object is not copy- and move-constructible
265 and not copy- and move-assignable.
267 template <size_t Count>
268 class GuardArray : public hp::array<Count>
271 typedef hp::array<Count> base_class;
274 /// Rebind array for other size \p Count2
275 template <size_t Count2>
277 typedef GuardArray<Count2> other ; ///< rebinding result
286 GuardArray( GuardArray const& ) = delete;
287 GuardArray( GuardArray&& ) = delete;
288 GuardArray& operator=(GuardArray const&) = delete;
289 GuardArray& operator=(GuardArray&&) = delete;
292 /// Protects a pointer of type \p atomic<T*>
294 Return the value of \p toGuard
296 The function tries to load \p toGuard and to store it
297 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
299 template <typename T>
300 T protect( size_t nIndex, atomics::atomic<T> const& toGuard )
304 pRet = assign( nIndex, toGuard.load(atomics::memory_order_acquire) );
305 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
310 /// Protects a pointer of type \p atomic<T*>
312 Return the value of \p toGuard
314 The function tries to load \p toGuard and to store it
315 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
317 The function is useful for intrusive containers when \p toGuard is a node pointer
318 that should be converted to a pointer to the value type before guarding.
319 The parameter \p f of type Func is a functor that makes this conversion:
322 value_type * operator()( T * p );
325 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
327 template <typename T, class Func>
328 T protect( size_t nIndex, atomics::atomic<T> const& toGuard, Func f )
332 assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_acquire) ));
333 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
338 /// Store \p to the slot \p nIndex
340 The function equals to a simple assignment, no loop is performed.
342 template <typename T>
343 T * assign( size_t nIndex, T * p ); // inline in hp_impl.h
345 /// Store marked pointer \p p to the guard
347 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
348 Can be used for a marked pointer that cannot be changed concurrently.
350 template <typename T, int BITMASK>
351 T * assign( size_t nIndex, cds::details::marked_ptr<T, BITMASK> p )
353 return assign( nIndex, p.ptr() );
356 /// Copy guarded value from \p src guard to slot at index \p nIndex
357 void copy( size_t nIndex, Guard const& src )
359 assign( nIndex, src.get_native() );
362 /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
363 void copy( size_t nDestIndex, size_t nSrcIndex )
365 assign( nDestIndex, get_native( nSrcIndex ));
368 /// Clear value of the slot \p nIndex
369 void clear( size_t nIndex )
371 base_class::clear( nIndex );
374 /// Get current value of slot \p nIndex
375 template <typename T>
376 T * get( size_t nIndex ) const
378 return reinterpret_cast<T *>( get_native( nIndex ) );
381 /// Get native hazard pointer stored
382 guarded_pointer get_native( size_t nIndex ) const
384 return base_class::operator[](nIndex).get();
387 /// Capacity of the guard array
388 static CDS_CONSTEXPR size_t capacity()
396 A guarded pointer is a pair of a pointer and GC's guard.
397 Usually, it is used for returning a pointer to the item from an lock-free container.
398 The guard prevents the pointer to be early disposed (freed) by GC.
399 After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time.
402 - \p GuardedType - a type which the guard stores
403 - \p ValueType - a value type
404 - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
406 For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
407 In such case the \p %guarded_ptr is:
409 typedef cds::gc::HP::guarded_ptr< foo > intrusive_guarded_ptr;
412 For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
420 struct value_accessor {
421 std::string* operator()( foo* pFoo ) const
423 return &(pFoo->value);
428 typedef cds::gc::HP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
431 You don't need use this class directly.
432 All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
434 template <typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
438 struct trivial_cast {
439 ValueType * operator()( GuardedType * p ) const
447 typedef GuardedType guarded_type; ///< Guarded type
448 typedef ValueType value_type; ///< Value type
450 /// Functor for casting \p guarded_type to \p value_type
451 typedef typename std::conditional< std::is_same<Cast, void>::value, trivial_cast, Cast >::type value_cast;
454 typedef cds::gc::hp::details::hp_guard native_guard;
459 native_guard * m_pGuard;
463 /// Creates empty guarded pointer
464 guarded_ptr() CDS_NOEXCEPT
471 /// Initializes guarded pointer with \p p
472 explicit guarded_ptr( guarded_type * p ) CDS_NOEXCEPT
473 : m_pGuard( nullptr )
477 explicit guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
478 : m_pGuard( nullptr )
483 guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
484 : m_pGuard( gp.m_pGuard )
486 gp.m_pGuard = nullptr;
489 /// The guarded pointer is not copy-constructible
490 guarded_ptr( guarded_ptr const& gp ) = delete;
492 /// Clears the guarded pointer
494 \ref release is called if guarded pointer is not \ref empty
496 ~guarded_ptr() CDS_NOEXCEPT
501 /// Move-assignment operator
502 guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
504 // Hazard Pointer array is organized as a stack
505 if ( m_pGuard && m_pGuard > gp.m_pGuard ) {
506 m_pGuard->set( gp.m_pGuard->get(atomics::memory_order_relaxed) );
511 m_pGuard = gp.m_pGuard;
512 gp.m_pGuard = nullptr;
517 /// The guarded pointer is not copy-assignable
518 guarded_ptr& operator=(guarded_ptr const& gp) = delete;
520 /// Returns a pointer to guarded value
521 value_type * operator ->() const CDS_NOEXCEPT
524 return value_cast()( reinterpret_cast<guarded_type *>(m_pGuard->get()));
527 /// Returns a reference to guarded value
528 value_type& operator *() CDS_NOEXCEPT
531 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
534 /// Returns const reference to guarded value
535 value_type const& operator *() const CDS_NOEXCEPT
538 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
541 /// Checks if the guarded pointer is \p nullptr
542 bool empty() const CDS_NOEXCEPT
544 return !m_pGuard || m_pGuard->get( atomics::memory_order_relaxed ) == nullptr;
547 /// \p bool operator returns <tt>!empty()</tt>
548 explicit operator bool() const CDS_NOEXCEPT
553 /// Clears guarded pointer
555 If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
556 Dereferncing the guarded pointer after \p release() is dangerous.
558 void release() CDS_NOEXCEPT
564 // For internal use only!!!
565 native_guard& guard() CDS_NOEXCEPT
572 void reset(guarded_type * p) CDS_NOEXCEPT
585 m_pGuard = &thread_gc::alloc_guard();
591 thread_gc::free_guard( *m_pGuard );
600 enum class scan_type {
601 classic = hp::classic, ///< classic scan as described in Michael's papers
602 inplace = hp::inplace ///< inplace scan without allocation
604 /// Initializes %HP singleton
606 The constructor initializes GC singleton with passed parameters.
607 If GC instance is not exist then the function creates the instance.
608 Otherwise it does nothing.
610 The Michael's %HP reclamation schema depends of three parameters:
611 - \p nHazardPtrCount - hazard pointer count per thread. Usually it is small number (up to 10) depending from
612 the data structure algorithms. By default, if \p nHazardPtrCount = 0, the function
613 uses maximum of the hazard pointer count for CDS library.
614 - \p nMaxThreadCount - max count of thread with using Hazard Pointer GC in your application. Default is 100.
615 - \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
616 <tt> nHazardPtrCount * nMaxThreadCount </tt>. Default is <tt>2 * nHazardPtrCount * nMaxThreadCount </tt>.
619 size_t nHazardPtrCount = 0, ///< Hazard pointer count per thread
620 size_t nMaxThreadCount = 0, ///< Max count of simultaneous working thread in your application
621 size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
622 scan_type nScanType = scan_type::inplace ///< Scan type (see \p scan_type enum)
625 hp::GarbageCollector::Construct(
629 static_cast<hp::scan_type>(nScanType)
633 /// Terminates GC singleton
635 The destructor destroys %HP global object. After calling of this function you may \b NOT
636 use CDS data structures based on \p %cds::gc::HP.
637 Usually, %HP object is destroyed at the end of your \p main().
641 hp::GarbageCollector::Destruct( true );
644 /// Checks if count of hazard pointer is no less than \p nCountNeeded
646 If \p bRaiseException is \p true (that is the default), the function raises
647 an \p std::overflow_error exception "Too few hazard pointers"
648 if \p nCountNeeded is more than the count of hazard pointer per thread.
650 static bool check_available_guards( size_t nCountNeeded, bool bRaiseException = true )
652 if ( hp::GarbageCollector::instance().getHazardPointerCount() < nCountNeeded ) {
653 if ( bRaiseException )
654 throw std::overflow_error( "Too few hazard pointers" );
660 /// Returns max Hazard Pointer count
661 static size_t max_hazard_count()
663 return hp::GarbageCollector::instance().getHazardPointerCount();
666 /// Returns max count of thread
667 static size_t max_thread_count()
669 return hp::GarbageCollector::instance().getMaxThreadCount();
672 /// Returns capacity of retired pointer array
673 static size_t retired_array_capacity()
675 return hp::GarbageCollector::instance().getMaxRetiredPtrCount();
678 /// Retire pointer \p p with function \p pFunc
680 The function places pointer \p p to array of pointers ready for removing.
681 (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
682 Deleting the pointer is the function \p pFunc call.
684 template <typename T>
685 static void retire( T * p, void (* pFunc)(T *) ); // inline in hp_impl.h
687 /// Retire pointer \p p with functor of type \p Disposer
689 The function places pointer \p p to array of pointers ready for removing.
690 (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
692 Deleting the pointer is an invocation of some object of type \p Disposer; the interface of \p Disposer is:
694 template <typename T>
696 void operator()( T * p ) ; // disposing operator
699 Since the functor call can happen at any time after \p retire call, additional restrictions are imposed to \p Disposer type:
700 - it should be stateless functor
701 - it should be default-constructible
702 - the result of functor call with argument \p p should not depend on where the functor will be called.
705 Operator \p delete functor:
707 template <typename T>
709 void operator ()( T * p ) {
714 // How to call GC::retire method
717 // ... use p in lock-free manner
719 cds::gc::HP::retire<disposer>( p ) ; // place p to retired pointer array of HP GC
722 Functor based on \p std::allocator :
724 template <typename ALLOC = std::allocator<int> >
726 template <typename T>
727 void operator()( T * p ) {
728 typedef typename ALLOC::templare rebind<T>::other alloc_t;
731 a.deallocate( p, 1 );
736 template <class Disposer, typename T>
737 static void retire( T * p ); // inline in hp_impl.h
739 /// Get current scan strategy
740 static scan_type getScanType()
742 return static_cast<scan_type>( hp::GarbageCollector::instance().getScanType());
745 /// Set current scan strategy
746 static void setScanType(
747 scan_type nScanType ///< new scan strategy
750 hp::GarbageCollector::instance().setScanType( static_cast<hp::scan_type>(nScanType) );
753 /// Checks if Hazard Pointer GC is constructed and may be used
756 return hp::GarbageCollector::isUsed();
759 /// Forced GC cycle call for current thread
761 Usually, this function should not be called directly.
763 static void scan() ; // inline in hp_impl.h
765 /// Synonym for \ref scan()
766 static void force_dispose()
771 }} // namespace cds::gc
773 #endif // #ifndef CDSLIB_GC_IMPL_HP_DECL_H