651d3127cdf81318a34630255ad57757de7765b9
[libcds.git] / cds / gc / dhp / dhp_decl.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_GC_DHP_DHP_DECL_H
4 #define __CDS_GC_DHP_DHP_DECL_H
5
6 #include <cds/gc/dhp/dhp.h>
7 #include <cds/details/marked_ptr.h>
8 #include <cds/details/static_functor.h>
9
10 namespace cds { namespace gc {
11
12     /// Dynamic Hazard Pointer garbage collector
13     /**  @ingroup cds_garbage_collector
14         @headerfile cds/gc/dhp.h
15         This class is a wrapper for Dynamic Hazard Pointer garbage collector internal implementation.
16
17         See \ref cds_how_to_use "How to use" section for details of garbage collector applying.
18     */
19     class DHP
20     {
21     public:
22         /// Native guarded pointer type
23         typedef void * guarded_pointer;
24
25         /// Atomic reference
26         /**
27             @headerfile cds/gc/dhp.h
28         */
29         template <typename T> using atomic_ref = atomics::atomic<T *>;
30
31         /// Atomic type
32         /**
33             @headerfile cds/gc/dhp.h
34         */
35         template <typename T> using atomic_type = atomics::atomic<T>;
36
37         /// Atomic marked pointer
38         /**
39             @headerfile cds/gc/dhp.h
40         */
41         template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
42
43         /// Thread GC implementation for internal usage
44         typedef dhp::ThreadGC   thread_gc_impl;
45
46         /// Wrapper for dhp::ThreadGC class
47         /**
48             @headerfile cds/gc/dhp.h
49             This class performs automatically attaching/detaching Dynamic Hazard Pointer GC
50             for the current thread.
51         */
52         class thread_gc: public thread_gc_impl
53         {
54             //@cond
55             bool    m_bPersistent;
56             //@endcond
57         public:
58             /// Constructor
59             /**
60                 The constructor attaches the current thread to the Dynamic Hazard Pointer GC
61                 if it is not yet attached.
62                 The \p bPersistent parameter specifies attachment persistence:
63                 - \p true - the class destructor will not detach the thread from Dynamic Hazard Pointer GC.
64                 - \p false (default) - the class destructor will detach the thread from Dynamic Hazard Pointer GC.
65             */
66             thread_gc(
67                 bool    bPersistent = false
68             )   ;   // inline in dhp_impl.h
69
70             /// Destructor
71             /**
72                 If the object has been created in persistent mode, the destructor does nothing.
73                 Otherwise it detaches the current thread from Dynamic Hazard Pointer GC.
74             */
75             ~thread_gc()    ;   // inline in dhp_impl.h
76         };
77
78
79         /// Dynamic Hazard Pointer guard
80         /**
81             @headerfile cds/gc/dhp.h
82             This class is a wrapper for dhp::Guard.
83         */
84         class Guard: public dhp::Guard
85         {
86             //@cond
87             typedef dhp::Guard base_class;
88             //@endcond
89
90         public:
91             //@cond
92             Guard() ;   // inline in dhp_impl.h
93             //@endcond
94
95             /// Protects a pointer of type <tt> atomic<T*> </tt>
96             /**
97                 Return the value of \p toGuard
98
99                 The function tries to load \p toGuard and to store it
100                 to the HP slot repeatedly until the guard's value equals \p toGuard
101             */
102             template <typename T>
103             T protect( atomics::atomic<T> const& toGuard )
104             {
105                 T pCur = toGuard.load(atomics::memory_order_relaxed);
106                 T pRet;
107                 do {
108                     pRet = assign( pCur );
109                     pCur = toGuard.load(atomics::memory_order_acquire);
110                 } while ( pRet != pCur );
111                 return pCur;
112             }
113
114             /// Protects a converted pointer of type <tt> atomic<T*> </tt>
115             /**
116                 Return the value of \p toGuard
117
118                 The function tries to load \p toGuard and to store result of \p f functor
119                 to the HP slot repeatedly until the guard's value equals \p toGuard.
120
121                 The function is useful for intrusive containers when \p toGuard is a node pointer
122                 that should be converted to a pointer to the value type before guarding.
123                 The parameter \p f of type Func is a functor that makes this conversion:
124                 \code
125                     struct functor {
126                         value_type * operator()( T * p );
127                     };
128                 \endcode
129                 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
130             */
131             template <typename T, class Func>
132             T protect( atomics::atomic<T> const& toGuard, Func f )
133             {
134                 T pCur = toGuard.load(atomics::memory_order_relaxed);
135                 T pRet;
136                 do {
137                     pRet = pCur;
138                     assign( f( pCur ) );
139                     pCur = toGuard.load(atomics::memory_order_acquire);
140                 } while ( pRet != pCur );
141                 return pCur;
142             }
143
144             /// Store \p p to the guard
145             /**
146                 The function equals to a simple assignment, no loop is performed.
147                 Can be used for a pointer that cannot be changed concurrently.
148             */
149             template <typename T>
150             T * assign( T * p )
151             {
152                 return base_class::operator =(p);
153             }
154
155             //@cond
156             std::nullptr_t assign( std::nullptr_t )
157             {
158                 return base_class::operator =(nullptr);
159             }
160             //@endcond
161
162             /// Store marked pointer \p p to the guard
163             /**
164                 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
165                 Can be used for a marked pointer that cannot be changed concurrently.
166             */
167             template <typename T, int BITMASK>
168             T * assign( cds::details::marked_ptr<T, BITMASK> p )
169             {
170                 return base_class::operator =( p.ptr() );
171             }
172
173             /// Copy from \p src guard to \p this guard
174             void copy( Guard const& src )
175             {
176                 assign( src.get_native() );
177             }
178
179             /// Clear value of the guard
180             void clear()
181             {
182                 base_class::clear();
183             }
184
185             /// Get the value currently protected (relaxed read)
186             template <typename T>
187             T * get() const
188             {
189                 return reinterpret_cast<T *>( get_native() );
190             }
191
192             /// Get native guarded pointer stored
193             guarded_pointer get_native() const
194             {
195                 return base_class::get_guard()->pPost.load(atomics::memory_order_relaxed);
196             }
197
198         };
199
200         /// Array of Dynamic Hazard Pointer guards
201         /**
202             @headerfile cds/gc/dhp.h
203             This class is a wrapper for dhp::GuardArray template.
204             Template parameter \p Count defines the size of DHP array.
205         */
206         template <size_t Count>
207         class GuardArray: public dhp::GuardArray<Count>
208         {
209             //@cond
210             typedef dhp::GuardArray<Count> base_class;
211             //@endcond
212         public:
213             /// Rebind array for other size \p COUNT2
214             template <size_t OtherCount>
215             struct rebind {
216                 typedef GuardArray<OtherCount>  other   ;   ///< rebinding result
217             };
218
219         public:
220             //@cond
221             GuardArray()    ;   // inline in dhp_impl.h
222             //@endcond
223
224             /// Protects a pointer of type \p atomic<T*>
225             /**
226                 Return the value of \p toGuard
227
228                 The function tries to load \p toGuard and to store it
229                 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
230             */
231             template <typename T>
232             T protect(size_t nIndex, atomics::atomic<T> const& toGuard )
233             {
234                 T pRet;
235                 do {
236                     pRet = assign( nIndex, toGuard.load(atomics::memory_order_relaxed) );
237                 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
238
239                 return pRet;
240             }
241
242             /// Protects a pointer of type \p atomic<T*>
243             /**
244                 Return the value of \p toGuard
245
246                 The function tries to load \p toGuard and to store it
247                 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
248
249                 The function is useful for intrusive containers when \p toGuard is a node pointer
250                 that should be converted to a pointer to the value type before guarding.
251                 The parameter \p f of type Func is a functor that makes this conversion:
252                 \code
253                     struct functor {
254                         value_type * operator()( T * p );
255                     };
256                 \endcode
257                 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
258             */
259             template <typename T, class Func>
260             T protect(size_t nIndex, atomics::atomic<T> const& toGuard, Func f )
261             {
262                 T pRet;
263                 do {
264                     assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_relaxed) ));
265                 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
266
267                 return pRet;
268             }
269
270             /// Store \p to the slot \p nIndex
271             /**
272                 The function equals to a simple assignment, no loop is performed.
273             */
274             template <typename T>
275             T * assign( size_t nIndex, T * p )
276             {
277                 base_class::set(nIndex, p);
278                 return p;
279             }
280
281             /// Store marked pointer \p p to the guard
282             /**
283                 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
284                 Can be used for a marked pointer that cannot be changed concurrently.
285             */
286             template <typename T, int Bitmask>
287             T * assign( size_t nIndex, cds::details::marked_ptr<T, Bitmask> p )
288             {
289                 return assign( nIndex, p.ptr() );
290             }
291
292             /// Copy guarded value from \p src guard to slot at index \p nIndex
293             void copy( size_t nIndex, Guard const& src )
294             {
295                 assign( nIndex, src.get_native() );
296             }
297
298             /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
299             void copy( size_t nDestIndex, size_t nSrcIndex )
300             {
301                 assign( nDestIndex, get_native( nSrcIndex ));
302             }
303
304             /// Clear value of the slot \p nIndex
305             void clear( size_t nIndex)
306             {
307                 base_class::clear( nIndex );
308             }
309
310             /// Get current value of slot \p nIndex
311             template <typename T>
312             T * get( size_t nIndex) const
313             {
314                 return reinterpret_cast<T *>( get_native( nIndex ) );
315             }
316
317             /// Get native guarded pointer stored
318             guarded_pointer get_native( size_t nIndex ) const
319             {
320                 return base_class::operator[](nIndex).get_guard()->pPost.load(atomics::memory_order_relaxed);
321             }
322
323             /// Capacity of the guard array
324             static CDS_CONSTEXPR size_t capacity()
325             {
326                 return Count;
327             }
328         };
329
330     public:
331         /// Initializes dhp::GarbageCollector singleton
332         /**
333             The constructor calls GarbageCollector::Construct with passed parameters.
334             See dhp::GarbageCollector::Construct for explanation of parameters meaning.
335         */
336         DHP(
337             size_t nLiberateThreshold = 1024
338             , size_t nInitialThreadGuardCount = 8
339         )
340         {
341             dhp::GarbageCollector::Construct(
342                 nLiberateThreshold,
343                 nInitialThreadGuardCount
344             );
345         }
346
347         /// Terminates dhp::GarbageCollector singleton
348         /**
349             The destructor calls \code dhp::GarbageCollector::Destruct() \endcode
350         */
351         ~DHP()
352         {
353             dhp::GarbageCollector::Destruct();
354         }
355
356         /// Checks if count of hazard pointer is no less than \p nCountNeeded
357         /**
358             The function always returns \p true since the guard count is unlimited for
359             DHP garbage collector.
360         */
361         static bool check_available_guards( size_t nCountNeeded, bool /*bRaiseException*/ = true )
362         {
363             CDS_UNUSED( nCountNeeded );
364             return true;
365         }
366
367         /// Retire pointer \p p with function \p pFunc
368         /**
369             The function places pointer \p p to array of pointers ready for removing.
370             (so called retired pointer array). The pointer can be safely removed when no guarded pointer points to it.
371             Deleting the pointer is the function \p pFunc call.
372         */
373         template <typename T>
374         static void retire( T * p, void (* pFunc)(T *) )
375         {
376             dhp::GarbageCollector::instance().retirePtr( p, pFunc );
377         }
378
379         /// Retire pointer \p p with functor of type \p Disposer
380         /**
381             The function places pointer \p p to array of pointers ready for removing.
382             (so called retired pointer array). The pointer can be safely removed when no guarded pointer points to it.
383
384             See gc::HP::retire for \p Disposer requirements.
385         */
386         template <class Disposer, typename T>
387         static void retire( T * p )
388         {
389             retire( p, cds::details::static_functor<Disposer, T>::call );
390         }
391
392         /// Checks if Dynamic Hazard Pointer GC is constructed and may be used
393         static bool isUsed()
394         {
395             return dhp::GarbageCollector::isUsed();
396         }
397
398         /// Forced GC cycle call for current thread
399         /**
400             Usually, this function should not be called directly.
401         */
402         static void scan()  ;   // inline in dhp_impl.h
403
404         /// Synonym for \ref scan()
405         static void force_dispose()
406         {
407             scan();
408         }
409     };
410
411 }} // namespace cds::gc
412
413 #endif // #ifndef __CDS_GC_DHP_DHP_DECL_H