2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
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
91 static bool const c_bBuffered = true ; ///< This RCU buffers disposed elements
95 typedef details::sh_singleton_instance< rcu_tag > singleton_ptr;
100 buffer_type m_Buffer;
101 atomics::atomic<uint64_t> m_nCurEpoch;
103 size_t const m_nCapacity;
107 /// Returns singleton instance
108 static signal_buffered * instance()
110 return static_cast<signal_buffered *>( base_class::instance());
112 /// Checks if the singleton is created and ready to use
115 return singleton_ptr::s_pRCU != nullptr;
120 signal_buffered( size_t nBufferCapacity, int nSignal = SIGUSR1 )
121 : base_class( nSignal )
122 , m_Buffer( nBufferCapacity )
124 , m_nCapacity( nBufferCapacity )
129 clear_buffer( std::numeric_limits< uint64_t >::max());
132 void clear_buffer( uint64_t nEpoch )
135 while ( m_Buffer.pop( p )) {
136 if ( p.m_nEpoch <= nEpoch ) {
140 push_buffer( std::move(p));
146 bool push_buffer( epoch_retired_ptr&& ep )
148 bool bPushed = m_Buffer.push( ep );
149 if ( !bPushed || m_Buffer.size() >= capacity()) {
161 /// Creates singleton object
163 The \p nBufferCapacity parameter defines RCU threshold.
165 The \p nSignal parameter defines a signal number stated for RCU, default is \p SIGUSR1
167 static void Construct( size_t nBufferCapacity = 256, int nSignal = SIGUSR1 )
169 if ( !singleton_ptr::s_pRCU )
170 singleton_ptr::s_pRCU = new signal_buffered( nBufferCapacity, nSignal );
173 /// Destroys singleton object
174 static void Destruct( bool bDetachAll = false )
177 instance()->clear_buffer( std::numeric_limits< uint64_t >::max());
179 instance()->m_ThreadList.detach_all();
181 singleton_ptr::s_pRCU = nullptr;
186 /// Retire \p p pointer
188 The method pushes \p p pointer to internal buffer.
189 When the buffer becomes full \ref synchronize function is called
190 to wait for the end of grace period and then to free all pointers from the buffer.
192 virtual void retire_ptr( retired_ptr& p )
195 push_buffer( epoch_retired_ptr( p, m_nCurEpoch.load( atomics::memory_order_relaxed )));
198 /// Retires the pointer chain [\p itFirst, \p itLast)
199 template <typename ForwardIterator>
200 void batch_retire( ForwardIterator itFirst, ForwardIterator itLast )
202 uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed );
203 while ( itFirst != itLast ) {
204 epoch_retired_ptr ep( *itFirst, nEpoch );
206 push_buffer( std::move(ep));
210 /// Retires the pointer chain until \p Func returns \p nullptr retired pointer
211 template <typename Func>
212 void batch_retire( Func e )
214 uint64_t nEpoch = m_nCurEpoch.load( atomics::memory_order_relaxed );
215 for ( retired_ptr p{ e() }; p.m_p; ) {
216 epoch_retired_ptr ep( p, nEpoch );
218 push_buffer( std::move(ep));
222 /// Wait to finish a grace period and then clear the buffer
225 epoch_retired_ptr ep( retired_ptr(), m_nCurEpoch.load( atomics::memory_order_relaxed ));
230 bool synchronize( epoch_retired_ptr& ep )
233 atomics::atomic_thread_fence( atomics::memory_order_acquire );
235 std::unique_lock<lock_type> sl( m_Lock );
236 if ( ep.m_p && m_Buffer.push( ep ) && m_Buffer.size() < capacity())
238 nEpoch = m_nCurEpoch.fetch_add( 1, atomics::memory_order_relaxed );
241 base_class::force_membar_all_threads( bkOff );
242 base_class::switch_next_epoch();
244 base_class::wait_for_quiescent_state( bkOff );
245 base_class::switch_next_epoch();
247 base_class::wait_for_quiescent_state( bkOff );
248 base_class::force_membar_all_threads( bkOff );
251 clear_buffer( nEpoch );
256 /// Returns the threshold of internal buffer
257 size_t capacity() const
262 /// Returns the signal number stated for RCU
263 int signal_no() const
265 return base_class::signal_no();
270 /// User-space signal-handled RCU with deferred (buffered) reclamation (stripped version)
272 @headerfile cds/urcu/signal_buffered.h
274 This short version of \p signal_buffered is intended for stripping debug info.
275 If you use \p %signal_buffered with default template arguments you may use
276 this stripped version. All functionality of both classes are identical.
278 class signal_buffered_stripped: public signal_buffered<>
281 }} // namespace cds::urcu
283 #endif // #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
284 #endif // #ifndef CDSLIB_URCU_DETAILS_SIG_BUFFERED_H