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_DETAILS_HP_ALLOC_H
32 #define CDSLIB_GC_DETAILS_HP_ALLOC_H
34 #include <cds/algo/atomic.h>
35 #include <cds/details/allocator.h>
36 #include <cds/gc/details/hp_type.h>
40 namespace gc { namespace hp {
42 class GarbageCollector;
45 /// Hazard Pointer schema implementation details
48 /// Hazard pointer guard
50 It is unsafe to use this class directly.
51 Instead, the \p hp::guard class should be used.
53 class hp_guard : protected atomics::atomic < hazard_pointer >
56 typedef hazard_pointer hazard_ptr; ///< Hazard pointer type
58 typedef atomics::atomic<hazard_ptr> base_class;
61 template <class Allocator> friend class hp_allocator;
64 hp_guard() CDS_NOEXCEPT
65 : base_class( nullptr )
67 ~hp_guard() CDS_NOEXCEPT
70 /// Sets HP value. Guards pointer \p p from reclamation.
72 Storing has release semantics.
75 T * operator =(T * p) CDS_NOEXCEPT
77 // We use atomic store with explicit memory order because other threads may read this hazard pointer concurrently
82 std::nullptr_t operator=(std::nullptr_t) CDS_NOEXCEPT
88 /// Returns current value of hazard pointer
90 Loading has acquire semantics
92 operator hazard_ptr() const CDS_NOEXCEPT
97 /// Returns current value of hazard pointer
99 Loading has acquire semantics
101 hazard_ptr get( atomics::memory_order order = atomics::memory_order_acquire ) const CDS_NOEXCEPT
103 return base_class::load( order );
106 template <typename T>
107 void set( T * p, atomics::memory_order order = atomics::memory_order_release ) CDS_NOEXCEPT
109 base_class::store( reinterpret_cast<hazard_ptr>(p), order );
114 Clearing has relaxed semantics.
116 void clear( atomics::memory_order order = atomics::memory_order_release ) CDS_NOEXCEPT
118 // memory order is not necessary here
119 base_class::store( nullptr, order );
123 /// Array of hazard pointers.
125 Array of hazard-pointer. Placing a pointer into this array guards the pointer against reclamation.
126 Template parameter \p Count defines the size of hazard pointer array. \p Count parameter should not exceed
127 GarbageCollector::getHazardPointerCount().
129 It is unsafe to use this class directly. Instead, the \p hp::array should be used.
131 While creating the object of \p hp_array class an array of size \p Count of hazard pointers is reserved by
132 the HP Manager of current thread. The object's destructor cleans all of reserved hazard pointer and
133 returns reserved HP to the HP pool of ThreadGC.
135 Usually, it is not necessary to create an object of this class. The object of class ThreadGC contains
136 the \p hp_array object and implements interface for HP setting and freeing.
139 \li Count - capacity of array
142 template <size_t Count>
146 typedef hazard_pointer hazard_ptr_type; ///< Hazard pointer type
147 typedef hp_guard atomic_hazard_ptr; ///< Element type of the array
148 static CDS_CONSTEXPR const size_t c_nCapacity = Count ; ///< Capacity of the array
151 atomic_hazard_ptr * m_arr ; ///< Hazard pointer array of size = \p Count
152 template <class Allocator> friend class hp_allocator;
155 /// Constructs uninitialized array.
156 hp_array() CDS_NOEXCEPT
160 ~hp_array() CDS_NOEXCEPT
163 /// Returns max count of hazard pointer for this array
164 CDS_CONSTEXPR size_t capacity() const
169 /// Set hazard pointer \p nIndex. 0 <= \p nIndex < \p Count
170 void set( size_t nIndex, hazard_ptr_type hzPtr ) CDS_NOEXCEPT
172 assert( nIndex < capacity() );
173 m_arr[nIndex] = hzPtr;
176 /// Returns reference to hazard pointer of index \p nIndex (0 <= \p nIndex < \p Count)
177 atomic_hazard_ptr& operator []( size_t nIndex ) CDS_NOEXCEPT
179 assert( nIndex < capacity() );
180 return m_arr[nIndex];
183 /// Returns reference to hazard pointer of index \p nIndex (0 <= \p nIndex < \p Count) [const version]
184 atomic_hazard_ptr& operator []( size_t nIndex ) const CDS_NOEXCEPT
186 assert( nIndex < capacity() );
187 return m_arr[nIndex];
190 /// Clears (sets to \p nullptr) hazard pointer \p nIndex
191 void clear( size_t nIndex ) CDS_NOEXCEPT
193 assert( nIndex < capacity() );
194 m_arr[ nIndex ].clear();
198 /// Allocator of hazard pointers for the thread
200 The hazard pointer array is the free-list of unused hazard pointer for the thread.
201 The array is managed as a stack.
202 The max size (capacity) of array is defined at ctor time and cannot be changed during object's lifetime
204 Each allocator object is thread-private.
207 \li Allocator - memory allocator class, default is \ref CDS_DEFAULT_ALLOCATOR
209 This helper class should not be used directly.
211 template <class Allocator = CDS_DEFAULT_ALLOCATOR >
215 typedef hazard_pointer hazard_ptr_type; ///< type of hazard pointer
216 typedef hp_guard atomic_hazard_ptr; ///< Atomic hazard pointer type
217 typedef Allocator allocator_type; ///< allocator type
220 typedef cds::details::Allocator< atomic_hazard_ptr, allocator_type > allocator_impl;
222 atomic_hazard_ptr * m_arrHazardPtr ; ///< Array of hazard pointers
223 size_t m_nTop ; ///< The top of stack
224 const size_t m_nCapacity ; ///< Array capacity
228 explicit hp_allocator(
229 size_t nCapacity ///< max count of hazard pointer per thread
231 : m_arrHazardPtr( alloc_array( nCapacity ) )
232 , m_nCapacity( nCapacity )
240 allocator_impl().Delete( m_arrHazardPtr, capacity() );
243 /// Get capacity of array
244 size_t capacity() const CDS_NOEXCEPT
249 /// Get size of array. The size is equal to the capacity of array
250 size_t size() const CDS_NOEXCEPT
255 /// Checks if all items are allocated
256 bool isFull() const CDS_NOEXCEPT
261 /// Allocates hazard pointer
262 atomic_hazard_ptr& alloc()
264 assert( m_nTop > 0 );
266 return m_arrHazardPtr[m_nTop];
269 /// Frees previously allocated hazard pointer
270 void free( atomic_hazard_ptr& hp ) CDS_NOEXCEPT
272 assert( m_nTop < capacity() );
277 /// Allocates hazard pointers array
279 Allocates \p Count hazard pointers from array \p m_arrHazardPtr
280 Returns initialized object \p arr
282 template <size_t Count>
283 void alloc( hp_array<Count>& arr )
285 assert( m_nTop >= Count );
287 arr.m_arr = m_arrHazardPtr + m_nTop;
290 /// Frees hazard pointer array
292 Frees the array of hazard pointers allocated by previous call \p this->alloc.
294 template <size_t Count>
295 void free( hp_array<Count> const& arr ) CDS_NOEXCEPT
299 assert( m_nTop + Count <= capacity());
300 for ( size_t i = m_nTop; i < m_nTop + Count; ++i )
301 m_arrHazardPtr[i].clear();
305 /// Makes all HP free
306 void clear() CDS_NOEXCEPT
311 /// Returns to i-th hazard pointer
312 atomic_hazard_ptr& operator []( size_t i ) CDS_NOEXCEPT
314 assert( i < capacity() );
315 return m_arrHazardPtr[i];
319 void make_free() CDS_NOEXCEPT
321 for ( size_t i = 0; i < capacity(); ++i )
322 m_arrHazardPtr[i].clear();
326 atomic_hazard_ptr * alloc_array( size_t nCapacity )
328 return allocator_impl().NewArray( nCapacity );
332 }}} // namespace gc::hp::details
336 #endif // #ifndef CDSLIB_GC_DETAILS_HP_ALLOC_H