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