Added simplified form of urcu::batch_retire function
[libcds.git] / cds / urcu / details / gpi.h
1 //$$CDS-header$$
2
3 #ifndef CDSLIB_URCU_DETAILS_GPI_H
4 #define CDSLIB_URCU_DETAILS_GPI_H
5
6 #include <mutex>
7 #include <cds/urcu/details/gp.h>
8 #include <cds/algo/backoff_strategy.h>
9
10 namespace cds { namespace urcu {
11
12     /// User-space general-purpose RCU with immediate reclamation
13     /**
14         @headerfile cds/urcu/general_instant.h
15
16         This is simplest general-purpose RCU implementation. When a thread calls \ref retire_ptr function
17         the RCU \p synchronize function is called that waits until all reader/updater threads end up
18         their read-side critical sections, i.e. until the RCU quiescent state will come.
19         After that the retired object is freed immediately.
20         Thus, the implementation blocks for any retired object
21
22         There is a wrapper \ref cds_urcu_general_instant_gc "gc<general_instant>" for \p %general_instant class
23         that provides unified RCU interface. You should use this wrapper class instead \p %general_instant
24
25         Template arguments:
26         - \p Lock - mutex type, default is \p std::mutex
27         - \p Backoff - back-off schema, default is cds::backoff::Default
28     */
29     template <
30         class Lock = std::mutex
31        ,class Backoff = cds::backoff::Default
32     >
33     class general_instant: public details::gp_singleton< general_instant_tag >
34     {
35         //@cond
36         typedef details::gp_singleton< general_instant_tag > base_class;
37         //@endcond
38
39     public:
40         typedef general_instant_tag rcu_tag ;   ///< RCU tag
41         typedef Lock    lock_type   ;           ///< Lock type
42         typedef Backoff back_off    ;           ///< Back-off schema type
43
44         typedef typename base_class::thread_gc  thread_gc ;   ///< Thread-side RCU part
45         typedef typename thread_gc::scoped_lock scoped_lock ; ///< Access lock class
46
47         static bool const c_bBuffered = false ; ///< This RCU does not buffer disposed elements
48
49     protected:
50         //@cond
51         typedef details::gp_singleton_instance< rcu_tag >    singleton_ptr;
52         //@endcond
53
54     protected:
55         //@cond
56         lock_type   m_Lock;
57         //@endcond
58
59     public:
60         /// Returns singleton instance
61         static general_instant * instance()
62         {
63             return static_cast<general_instant *>( base_class::instance() );
64         }
65
66         /// Checks if the singleton is created and ready to use
67         static bool isUsed()
68         {
69             return singleton_ptr::s_pRCU != nullptr;
70         }
71
72     protected:
73         //@cond
74         general_instant()
75         {}
76         ~general_instant()
77         {}
78
79         void flip_and_wait()
80         {
81             back_off bkoff;
82             base_class::flip_and_wait( bkoff );
83         }
84         //@endcond
85
86     public:
87         /// Creates singleton object
88         static void Construct()
89         {
90             if ( !singleton_ptr::s_pRCU )
91                 singleton_ptr::s_pRCU = new general_instant();
92         }
93
94         /// Destroys singleton object
95         static void Destruct( bool bDetachAll = false )
96         {
97             if ( isUsed() ) {
98                 if ( bDetachAll )
99                     instance()->m_ThreadList.detach_all();
100                 delete instance();
101                 singleton_ptr::s_pRCU = nullptr;
102             }
103         }
104
105     public:
106         /// Retires \p p pointer
107         /**
108             The method calls \ref synchronize to wait for the end of grace period
109             and calls \p p disposer.
110         */
111         virtual void retire_ptr( retired_ptr& p )
112         {
113             synchronize();
114             if ( p.m_p )
115                 p.free();
116         }
117
118         /// Retires the pointer chain [\p itFirst, \p itLast)
119         template <typename ForwardIterator>
120         void batch_retire( ForwardIterator itFirst, ForwardIterator itLast )
121         {
122             if ( itFirst != itLast ) {
123                 synchronize();
124                 while ( itFirst != itLast ) {
125                     retired_ptr p( *itFirst );
126                     ++itFirst;
127                     if ( p.m_p )
128                         p.free();
129                 }
130             }
131         }
132
133         /// Retires the pointer chain until \p Func returns \p nullptr retired pointer
134         template <typename Func>
135         void batch_retire( Func e )
136         {
137             retired_ptr p{ e() };
138             if ( p.m_p ) {
139                 synchronize();
140                 for ( ; p.m_p; p = e() )
141                     p.free();
142             }
143         }
144
145         /// Waits to finish a grace period
146         void synchronize()
147         {
148             atomics::atomic_thread_fence( atomics::memory_order_acquire );
149             {
150                 std::unique_lock<lock_type> sl( m_Lock );
151                 flip_and_wait();
152                 flip_and_wait();
153             }
154             atomics::atomic_thread_fence( atomics::memory_order_release );
155         }
156
157         //@cond
158         // Added for uniformity
159         size_t CDS_CONSTEXPR capacity() const
160         {
161             return 1;
162         }
163         //@endcond
164     };
165
166 }} // namespace cds::urcu
167
168 #endif // #ifndef CDSLIB_URCU_DETAILS_GPI_H