fixed adding file problem
[c11concurrency-benchmarks.git] / gdax-orderbook-hpp / demo / dependencies / libcds-2.3.2 / cds / urcu / details / sig_buffered.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
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.
18
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.
29 */
30
31 #ifndef CDSLIB_URCU_DETAILS_SIG_BUFFERED_H
32 #define CDSLIB_URCU_DETAILS_SIG_BUFFERED_H
33
34 #include <cds/urcu/details/sh.h>
35 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
36
37 #include <mutex>
38 #include <limits>
39 #include <cds/algo/backoff_strategy.h>
40 #include <cds/container/vyukov_mpmc_cycle_queue.h>
41
42 namespace cds { namespace urcu {
43
44     /// User-space signal-handled RCU with deferred (buffered) reclamation
45     /**
46         @headerfile cds/urcu/signal_buffered.h
47
48         This URCU implementation contains an internal buffer where retired objects are
49         accumulated. When the buffer becomes full, the RCU \p synchronize function is called
50         that waits until all reader/updater threads end up their read-side critical sections,
51         i.e. until the RCU quiescent state will come. After that the buffer and all retired objects are freed.
52         This synchronization cycle may be called in any thread that calls \p retire_ptr function.
53
54         The \p Buffer contains items of \ref cds_urcu_retired_ptr "retired_ptr" type and it should support a queue interface with
55         three function:
56         - <tt> bool push( retired_ptr& p ) </tt> - places the retired pointer \p p into queue. If the function
57             returns \p false it means that the buffer is full and RCU synchronization cycle must be processed.
58         - <tt>bool pop( retired_ptr& p ) </tt> - pops queue's head item into \p p parameter; if the queue is empty
59             this function must return \p false
60         - <tt>size_t size()</tt> - returns queue's item count.
61
62         The buffer is considered as full if \p push returns \p false or the buffer size reaches the RCU threshold.
63
64         There is a wrapper \ref cds_urcu_signal_buffered_gc "gc<signal_buffered>" for \p %signal_buffered class
65         that provides unified RCU interface. You should use this wrapper class instead \p %signal_buffered
66
67         Template arguments:
68         - \p Buffer - buffer type. Default is cds::container::VyukovMPMCCycleQueue
69         - \p Lock - mutex type, default is \p std::mutex
70         - \p Backoff - back-off schema, default is cds::backoff::Default
71     */
72     template <
73         class Buffer = cds::container::VyukovMPMCCycleQueue< epoch_retired_ptr >
74         ,class Lock = std::mutex
75         ,class Backoff = cds::backoff::Default
76     >
77     class signal_buffered: public details::sh_singleton< signal_buffered_tag >
78     {
79         //@cond
80         typedef details::sh_singleton< signal_buffered_tag > base_class;
81         //@endcond
82     public:
83         typedef signal_buffered_tag rcu_tag ;  ///< RCU tag
84         typedef Buffer  buffer_type ;   ///< Buffer type
85         typedef Lock    lock_type   ;   ///< Lock type
86         typedef Backoff back_off    ;   ///< Back-off type
87
88         typedef base_class::thread_gc thread_gc ;   ///< Thread-side RCU part
89         typedef typename thread_gc::scoped_lock scoped_lock ; ///< Access lock class
90
91         //@cond
92         static bool const c_bBuffered = true ; ///< Bufferized RCU
93         //@endcond
94
95     protected:
96         //@cond
97         typedef details::sh_singleton_instance< rcu_tag >    singleton_ptr;
98         //@endcond
99
100     protected:
101         //@cond
102         buffer_type               m_Buffer;
103         atomics::atomic<uint64_t> m_nCurEpoch;
104         lock_type                 m_Lock;
105         size_t const              m_nCapacity;
106         //@endcond
107
108     public:
109         /// Returns singleton instance
110         static signal_buffered * instance()
111         {
112             return static_cast<signal_buffered *>( base_class::instance());
113         }
114         /// Checks if the singleton is created and ready to use
115         static bool isUsed()
116         {
117             return singleton_ptr::s_pRCU != nullptr;
118         }
119
120     protected:
121         //@cond
122         signal_buffered( size_t nBufferCapacity, int nSignal = SIGUSR1 )
123             : base_class( nSignal )
124             , m_Buffer( nBufferCapacity )
125             , m_nCurEpoch(0)
126             , m_nCapacity( nBufferCapacity )
127         {}
128
129         ~signal_buffered()
130         {
131             clear_buffer( std::numeric_limits< uint64_t >::max());
132         }
133
134         void clear_buffer( uint64_t nEpoch )
135         {
136             epoch_retired_ptr p;
137             while ( m_Buffer.pop( p )) {
138                 if ( p.m_nEpoch <= nEpoch ) {
139                     p.free();
140                 }
141                 else {
142                     push_buffer( std::move(p));
143                     break;
144                 }
145             }
146         }
147
148         bool push_buffer( epoch_retired_ptr&& ep )
149         {
150             bool bPushed = m_Buffer.push( ep );
151             if ( !bPushed || m_Buffer.size() >= capacity()) {
152                 synchronize();
153                 if ( !bPushed ) {
154                     ep.free();
155                 }
156                 return true;
157             }
158             return false;
159         }
160         //@endcond
161
162     public:
163         /// Creates singleton object
164         /**
165             The \p nBufferCapacity parameter defines RCU threshold.
166
167             The \p nSignal parameter defines a signal number stated for RCU, default is \p SIGUSR1
168         */
169         static void Construct( size_t nBufferCapacity = 256, int nSignal = SIGUSR1 )
170         {
171             if ( !singleton_ptr::s_pRCU )
172                 singleton_ptr::s_pRCU = new signal_buffered( nBufferCapacity, nSignal );
173         }
174
175         /// Destroys singleton object
176         static void Destruct( bool bDetachAll = false )
177         {
178             if ( isUsed()) {
179                 instance()->clear_buffer( std::numeric_limits< uint64_t >::max());
180                 if ( bDetachAll )
181                     instance()->m_ThreadList.detach_all();
182                 delete instance();
183                 singleton_ptr::s_pRCU = nullptr;
184             }
185         }
186
187     public:
188         /// Retire \p p pointer
189         /**
190             The method pushes \p p pointer to internal buffer.
191             When the buffer becomes full \ref synchronize function is called
192             to wait for the end of grace period and then to free all pointers from the buffer.
193         */
194         virtual void retire_ptr( retired_ptr& p ) override
195         {
196             if ( p.m_p )
197                 push_buffer( epoch_retired_ptr( p, m_nCurEpoch.load( atomics::memory_order_relaxed )));
198         }
199
200         /// Retires the pointer chain [\p itFirst, \p itLast)
201         template <typename ForwardIterator>
202         void batch_retire( ForwardIterator itFirst, ForwardIterator itLast )
203         {
204             uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed );
205             while ( itFirst != itLast ) {
206                 epoch_retired_ptr ep( *itFirst, nEpoch );
207                 ++itFirst;
208                 push_buffer( std::move(ep));
209             }
210         }
211
212         /// Retires the pointer chain until \p Func returns \p nullptr retired pointer
213         template <typename Func>
214         void batch_retire( Func e )
215         {
216             uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed );
217             for ( retired_ptr p{ e() }; p.m_p; ) {
218                 epoch_retired_ptr ep( p, nEpoch );
219                 p = e();
220                 push_buffer( std::move(ep));
221             }
222         }
223
224         /// Wait to finish a grace period and then clear the buffer
225         void synchronize()
226         {
227             epoch_retired_ptr ep( retired_ptr(), m_nCurEpoch.load( atomics::memory_order_relaxed ));
228             synchronize( ep );
229         }
230
231         //@cond
232         bool synchronize( epoch_retired_ptr& ep )
233         {
234             uint64_t nEpoch;
235             {
236                 std::unique_lock<lock_type> sl( m_Lock );
237                 if ( ep.m_p && m_Buffer.push( ep ) && m_Buffer.size() < capacity())
238                     return false;
239                 nEpoch = m_nCurEpoch.fetch_add( 1, atomics::memory_order_relaxed );
240
241                 back_off bkOff;
242                 base_class::force_membar_all_threads( bkOff );
243                 base_class::switch_next_epoch();
244                 bkOff.reset();
245                 base_class::wait_for_quiescent_state( bkOff );
246                 base_class::switch_next_epoch();
247                 bkOff.reset();
248                 base_class::wait_for_quiescent_state( bkOff );
249                 base_class::force_membar_all_threads( bkOff );
250             }
251
252             clear_buffer( nEpoch );
253             return true;
254         }
255         //@endcond
256
257         /// Returns the threshold of internal buffer
258         size_t capacity() const
259         {
260             return m_nCapacity;
261         }
262
263         /// Returns the signal number stated for RCU
264         int signal_no() const
265         {
266             return base_class::signal_no();
267         }
268     };
269
270
271     /// User-space signal-handled RCU with deferred (buffered) reclamation (stripped version)
272     /**
273         @headerfile cds/urcu/signal_buffered.h
274
275         This short version of \p signal_buffered is intended for stripping debug info.
276         If you use \p %signal_buffered with default template arguments you may use
277         this stripped version. All functionality of both classes are identical.
278     */
279     class signal_buffered_stripped: public signal_buffered<>
280     {};
281
282 }} // namespace cds::urcu
283
284 #endif // #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
285 #endif // #ifndef CDSLIB_URCU_DETAILS_SIG_BUFFERED_H