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_SH_DECL_H
32 #define CDSLIB_URCU_DETAILS_SH_DECL_H
34 #include <cds/urcu/details/base.h>
36 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
37 #include <cds/details/static_functor.h>
38 #include <cds/details/lib.h>
43 namespace cds { namespace urcu { namespace details {
45 // We could derive thread_data from thread_list_record
46 // but in this case m_nAccessControl would have offset != 0
47 // that is not so efficiently
48 # define CDS_SHURCU_DECLARE_THREAD_DATA(tag_) \
49 template <> struct thread_data<tag_> { \
50 atomics::atomic<uint32_t> m_nAccessControl ; \
51 atomics::atomic<bool> m_bNeedMemBar ; \
52 thread_list_record< thread_data > m_list ; \
53 thread_data(): m_nAccessControl(0), m_bNeedMemBar(false) {} \
57 CDS_SHURCU_DECLARE_THREAD_DATA( signal_buffered_tag );
58 CDS_SHURCU_DECLARE_THREAD_DATA( signal_threaded_tag );
60 # undef CDS_SHURCU_DECLARE_THREAD_DATA
62 template <typename RCUtag>
63 struct sh_singleton_instance
65 static CDS_EXPORT_API singleton_vtbl * s_pRCU;
67 #if CDS_COMPILER != CDS_COMPILER_MSVC
68 template<> CDS_EXPORT_API singleton_vtbl * sh_singleton_instance< signal_buffered_tag >::s_pRCU;
69 template<> CDS_EXPORT_API singleton_vtbl * sh_singleton_instance< signal_threaded_tag >::s_pRCU;
72 template <typename SigRCUtag>
76 typedef SigRCUtag rcu_tag;
77 typedef typename rcu_tag::rcu_class rcu_class;
78 typedef thread_data< rcu_tag > thread_record;
79 typedef cds::urcu::details::scoped_lock< sh_thread_gc > scoped_lock;
82 static thread_record * get_thread_record();
88 static void access_lock();
89 static void access_unlock();
90 static bool is_locked();
92 /// Retire pointer \p by the disposer \p Disposer
93 template <typename Disposer, typename T>
94 static void retire( T * p )
96 retire( p, cds::details::static_functor<Disposer, T>::call );
99 /// Retire pointer \p by the disposer \p pFunc
100 template <typename T>
101 static void retire( T * p, void (* pFunc)(T *))
103 retired_ptr rp( reinterpret_cast<void *>( p ), reinterpret_cast<free_retired_ptr_func>( pFunc ));
107 /// Retire pointer \p
108 static void retire( retired_ptr& p )
110 assert( sh_singleton_instance< rcu_tag >::s_pRCU );
111 sh_singleton_instance< rcu_tag >::s_pRCU->retire_ptr( p );
115 # define CDS_SH_RCU_DECLARE_THREAD_GC( tag_ ) template <> class thread_gc<tag_>: public sh_thread_gc<tag_> {}
117 CDS_SH_RCU_DECLARE_THREAD_GC( signal_buffered_tag );
118 CDS_SH_RCU_DECLARE_THREAD_GC( signal_threaded_tag );
120 # undef CDS_SH_RCU_DECLARE_THREAD_GC
122 template <class RCUtag>
123 class sh_singleton: public singleton_vtbl
126 typedef RCUtag rcu_tag;
127 typedef cds::urcu::details::thread_gc< rcu_tag > thread_gc;
130 typedef typename thread_gc::thread_record thread_record;
131 typedef sh_singleton_instance< rcu_tag > rcu_instance;
134 atomics::atomic<uint32_t> m_nGlobalControl;
135 thread_list< rcu_tag > m_ThreadList;
139 sh_singleton( int nSignal )
140 : m_nGlobalControl(1)
141 , m_nSigNo( nSignal )
143 set_signal_handler();
148 clear_signal_handler();
152 static sh_singleton * instance()
154 return static_cast< sh_singleton *>( rcu_instance::s_pRCU );
159 return rcu_instance::s_pRCU != nullptr;
162 int signal_no() const
168 virtual void retire_ptr( retired_ptr& p ) = 0;
170 public: // thread_gc interface
171 thread_record * attach_thread()
173 return m_ThreadList.alloc();
176 void detach_thread( thread_record * pRec )
178 m_ThreadList.retire( pRec );
181 uint32_t global_control_word( atomics::memory_order mo ) const
183 return m_nGlobalControl.load( mo );
187 void set_signal_handler();
188 void clear_signal_handler();
189 static void signal_handler( int signo, siginfo_t * sigInfo, void * context );
190 void raise_signal( cds::OS::ThreadId tid );
192 template <class Backoff>
193 void force_membar_all_threads( Backoff& bkOff );
195 void switch_next_epoch()
197 m_nGlobalControl.fetch_xor( rcu_tag::c_nControlBit, atomics::memory_order_seq_cst );
199 bool check_grace_period( thread_record * pRec ) const;
201 template <class Backoff>
202 void wait_for_quiescent_state( Backoff& bkOff );
205 # define CDS_SIGRCU_DECLARE_SINGLETON( tag_ ) \
206 template <> class singleton< tag_ > { \
208 typedef tag_ rcu_tag ; \
209 typedef cds::urcu::details::thread_gc< rcu_tag > thread_gc ; \
211 typedef thread_gc::thread_record thread_record ; \
212 typedef sh_singleton_instance< rcu_tag > rcu_instance ; \
213 typedef sh_singleton< rcu_tag > rcu_singleton ; \
215 static bool isUsed() { return rcu_singleton::isUsed() ; } \
216 static rcu_singleton * instance() { assert( rcu_instance::s_pRCU ); return static_cast<rcu_singleton *>( rcu_instance::s_pRCU ); } \
217 static thread_record * attach_thread() { return instance()->attach_thread() ; } \
218 static void detach_thread( thread_record * pRec ) { return instance()->detach_thread( pRec ) ; } \
219 static uint32_t global_control_word( atomics::memory_order mo ) { return instance()->global_control_word( mo ) ; } \
222 CDS_SIGRCU_DECLARE_SINGLETON( signal_buffered_tag );
223 CDS_SIGRCU_DECLARE_SINGLETON( signal_threaded_tag );
225 # undef CDS_SIGRCU_DECLARE_SINGLETON
227 }}} // namespace cds::urcu::details
230 #endif // #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
231 #endif // #ifndef CDSLIB_URCU_DETAILS_SH_DECL_H