2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
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_URCU_DETAILS_SIG_BUFFERED_H
32 #define CDSLIB_URCU_DETAILS_SIG_BUFFERED_H
34 #include <cds/urcu/details/sh.h>
35 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
39 #include <cds/algo/backoff_strategy.h>
40 #include <cds/container/vyukov_mpmc_cycle_queue.h>
42 namespace cds { namespace urcu {
44 /// User-space signal-handled RCU with deferred (buffered) reclamation
46 @headerfile cds/urcu/signal_buffered.h
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.
54 The \p Buffer contains items of \ref cds_urcu_retired_ptr "retired_ptr" type and it should support a queue interface with
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.
62 The buffer is considered as full if \p push returns \p false or the buffer size reaches the RCU threshold.
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
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
73 class Buffer = cds::container::VyukovMPMCCycleQueue< epoch_retired_ptr >
74 ,class Lock = std::mutex
75 ,class Backoff = cds::backoff::Default
77 class signal_buffered: public details::sh_singleton< signal_buffered_tag >
80 typedef details::sh_singleton< signal_buffered_tag > base_class;
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
88 typedef base_class::thread_gc thread_gc ; ///< Thread-side RCU part
89 typedef typename thread_gc::scoped_lock scoped_lock ; ///< Access lock class
92 static bool const c_bBuffered = true ; ///< Bufferized RCU
97 typedef details::sh_singleton_instance< rcu_tag > singleton_ptr;
102 buffer_type m_Buffer;
103 atomics::atomic<uint64_t> m_nCurEpoch;
105 size_t const m_nCapacity;
109 /// Returns singleton instance
110 static signal_buffered * instance()
112 return static_cast<signal_buffered *>( base_class::instance());
114 /// Checks if the singleton is created and ready to use
117 return singleton_ptr::s_pRCU != nullptr;
122 signal_buffered( size_t nBufferCapacity, int nSignal = SIGUSR1 )
123 : base_class( nSignal )
124 , m_Buffer( nBufferCapacity )
126 , m_nCapacity( nBufferCapacity )
131 clear_buffer( std::numeric_limits< uint64_t >::max());
134 void clear_buffer( uint64_t nEpoch )
137 while ( m_Buffer.pop( p )) {
138 if ( p.m_nEpoch <= nEpoch ) {
142 push_buffer( std::move(p));
148 bool push_buffer( epoch_retired_ptr&& ep )
150 bool bPushed = m_Buffer.push( ep );
151 if ( !bPushed || m_Buffer.size() >= capacity()) {
163 /// Creates singleton object
165 The \p nBufferCapacity parameter defines RCU threshold.
167 The \p nSignal parameter defines a signal number stated for RCU, default is \p SIGUSR1
169 static void Construct( size_t nBufferCapacity = 256, int nSignal = SIGUSR1 )
171 if ( !singleton_ptr::s_pRCU )
172 singleton_ptr::s_pRCU = new signal_buffered( nBufferCapacity, nSignal );
175 /// Destroys singleton object
176 static void Destruct( bool bDetachAll = false )
179 instance()->clear_buffer( std::numeric_limits< uint64_t >::max());
181 instance()->m_ThreadList.detach_all();
183 singleton_ptr::s_pRCU = nullptr;
188 /// Retire \p p pointer
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.
194 virtual void retire_ptr( retired_ptr& p ) override
197 push_buffer( epoch_retired_ptr( p, m_nCurEpoch.load( atomics::memory_order_relaxed )));
200 /// Retires the pointer chain [\p itFirst, \p itLast)
201 template <typename ForwardIterator>
202 void batch_retire( ForwardIterator itFirst, ForwardIterator itLast )
204 uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed );
205 while ( itFirst != itLast ) {
206 epoch_retired_ptr ep( *itFirst, nEpoch );
208 push_buffer( std::move(ep));
212 /// Retires the pointer chain until \p Func returns \p nullptr retired pointer
213 template <typename Func>
214 void batch_retire( Func e )
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 );
220 push_buffer( std::move(ep));
224 /// Wait to finish a grace period and then clear the buffer
227 epoch_retired_ptr ep( retired_ptr(), m_nCurEpoch.load( atomics::memory_order_relaxed ));
232 bool synchronize( epoch_retired_ptr& ep )
236 std::unique_lock<lock_type> sl( m_Lock );
237 if ( ep.m_p && m_Buffer.push( ep ) && m_Buffer.size() < capacity())
239 nEpoch = m_nCurEpoch.fetch_add( 1, atomics::memory_order_relaxed );
242 base_class::force_membar_all_threads( bkOff );
243 base_class::switch_next_epoch();
245 base_class::wait_for_quiescent_state( bkOff );
246 base_class::switch_next_epoch();
248 base_class::wait_for_quiescent_state( bkOff );
249 base_class::force_membar_all_threads( bkOff );
252 clear_buffer( nEpoch );
257 /// Returns the threshold of internal buffer
258 size_t capacity() const
263 /// Returns the signal number stated for RCU
264 int signal_no() const
266 return base_class::signal_no();
271 /// User-space signal-handled RCU with deferred (buffered) reclamation (stripped version)
273 @headerfile cds/urcu/signal_buffered.h
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.
279 class signal_buffered_stripped: public signal_buffered<>
282 }} // namespace cds::urcu
284 #endif // #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
285 #endif // #ifndef CDSLIB_URCU_DETAILS_SIG_BUFFERED_H