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_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) {} \
54 explicit thread_data( OS::ThreadId owner ): m_nAccessControl(0), m_bNeedMemBar(false), m_list(owner) {} \
58 CDS_SHURCU_DECLARE_THREAD_DATA( signal_buffered_tag );
59 CDS_SHURCU_DECLARE_THREAD_DATA( signal_threaded_tag );
61 # undef CDS_SHURCU_DECLARE_THREAD_DATA
63 template <typename RCUtag>
64 struct sh_singleton_instance
66 static CDS_EXPORT_API singleton_vtbl * s_pRCU;
68 #if CDS_COMPILER != CDS_COMPILER_MSVC
69 template<> CDS_EXPORT_API singleton_vtbl * sh_singleton_instance< signal_buffered_tag >::s_pRCU;
70 template<> CDS_EXPORT_API singleton_vtbl * sh_singleton_instance< signal_threaded_tag >::s_pRCU;
73 template <typename SigRCUtag>
77 typedef SigRCUtag rcu_tag;
78 typedef typename rcu_tag::rcu_class rcu_class;
79 typedef thread_data< rcu_tag > thread_record;
80 typedef cds::urcu::details::scoped_lock< sh_thread_gc > scoped_lock;
83 static thread_record * get_thread_record();
90 static void access_lock();
91 static void access_unlock();
92 static bool is_locked();
94 /// Retire pointer \p by the disposer \p Disposer
95 template <typename Disposer, typename T>
96 static void retire( T * p )
98 retire( p, cds::details::static_functor<Disposer, T>::call );
101 /// Retire pointer \p by the disposer \p pFunc
102 template <typename T>
103 static void retire( T * p, void (* pFunc)(T *))
105 retired_ptr rp( reinterpret_cast<void *>( p ), reinterpret_cast<free_retired_ptr_func>( pFunc ));
109 /// Retire pointer \p
110 static void retire( retired_ptr& p )
112 assert( sh_singleton_instance< rcu_tag >::s_pRCU );
113 sh_singleton_instance< rcu_tag >::s_pRCU->retire_ptr( p );
117 # define CDS_SH_RCU_DECLARE_THREAD_GC( tag_ ) template <> class thread_gc<tag_>: public sh_thread_gc<tag_> {}
119 CDS_SH_RCU_DECLARE_THREAD_GC( signal_buffered_tag );
120 CDS_SH_RCU_DECLARE_THREAD_GC( signal_threaded_tag );
122 # undef CDS_SH_RCU_DECLARE_THREAD_GC
124 template <class RCUtag>
125 class sh_singleton: public singleton_vtbl
128 typedef RCUtag rcu_tag;
129 typedef cds::urcu::details::thread_gc< rcu_tag > thread_gc;
132 typedef typename thread_gc::thread_record thread_record;
133 typedef sh_singleton_instance< rcu_tag > rcu_instance;
136 atomics::atomic<uint32_t> m_nGlobalControl;
137 thread_list< rcu_tag > m_ThreadList;
141 sh_singleton( int nSignal )
142 : m_nGlobalControl(1)
143 , m_nSigNo( nSignal )
145 set_signal_handler();
150 clear_signal_handler();
154 static sh_singleton * instance()
156 return static_cast< sh_singleton *>( rcu_instance::s_pRCU );
161 return rcu_instance::s_pRCU != nullptr;
164 int signal_no() const
170 virtual void retire_ptr( retired_ptr& p ) = 0;
172 public: // thread_gc interface
173 thread_record * attach_thread()
175 return m_ThreadList.alloc();
178 void detach_thread( thread_record * pRec )
180 m_ThreadList.retire( pRec );
183 uint32_t global_control_word( atomics::memory_order mo ) const
185 return m_nGlobalControl.load( mo );
189 void set_signal_handler();
190 void clear_signal_handler();
191 static void signal_handler( int signo, siginfo_t * sigInfo, void * context );
192 void raise_signal( cds::OS::ThreadId tid );
194 template <class Backoff>
195 void force_membar_all_threads( Backoff& bkOff );
197 void switch_next_epoch()
199 m_nGlobalControl.fetch_xor( rcu_tag::c_nControlBit, atomics::memory_order_seq_cst );
201 bool check_grace_period( thread_record * pRec ) const;
203 template <class Backoff>
204 void wait_for_quiescent_state( Backoff& bkOff );
207 # define CDS_SIGRCU_DECLARE_SINGLETON( tag_ ) \
208 template <> class singleton< tag_ > { \
210 typedef tag_ rcu_tag ; \
211 typedef cds::urcu::details::thread_gc< rcu_tag > thread_gc ; \
213 typedef thread_gc::thread_record thread_record ; \
214 typedef sh_singleton_instance< rcu_tag > rcu_instance ; \
215 typedef sh_singleton< rcu_tag > rcu_singleton ; \
217 static bool isUsed() { return rcu_singleton::isUsed() ; } \
218 static rcu_singleton * instance() { assert( rcu_instance::s_pRCU ); return static_cast<rcu_singleton *>( rcu_instance::s_pRCU ); } \
219 static thread_record * attach_thread() { return instance()->attach_thread() ; } \
220 static void detach_thread( thread_record * pRec ) { return instance()->detach_thread( pRec ) ; } \
221 static uint32_t global_control_word( atomics::memory_order mo ) { return instance()->global_control_word( mo ) ; } \
224 CDS_SIGRCU_DECLARE_SINGLETON( signal_buffered_tag );
225 CDS_SIGRCU_DECLARE_SINGLETON( signal_threaded_tag );
227 # undef CDS_SIGRCU_DECLARE_SINGLETON
229 }}} // namespace cds::urcu::details
232 #endif // #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
233 #endif // #ifndef CDSLIB_URCU_DETAILS_SH_DECL_H