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>
39 #include <cds/user_setup/cache_line.h>
44 namespace cds { namespace urcu { namespace details {
46 // We could derive thread_data from thread_list_record
47 // but in this case m_nAccessControl would have offset != 0
48 // that is not so efficiently
49 # define CDS_SHURCU_DECLARE_THREAD_DATA(tag_) \
50 template <> struct thread_data<tag_> { \
51 atomics::atomic<uint32_t> m_nAccessControl ; \
52 atomics::atomic<bool> m_bNeedMemBar ; \
53 thread_list_record< thread_data > m_list ; \
54 char pad_[cds::c_nCacheLineSize]; \
55 thread_data(): m_nAccessControl(0), m_bNeedMemBar(false) {} \
56 explicit thread_data( OS::ThreadId owner ): m_nAccessControl(0), m_bNeedMemBar(false), m_list(owner) {} \
60 CDS_SHURCU_DECLARE_THREAD_DATA( signal_buffered_tag );
62 # undef CDS_SHURCU_DECLARE_THREAD_DATA
64 template <typename RCUtag>
65 struct sh_singleton_instance
67 static CDS_EXPORT_API singleton_vtbl * s_pRCU;
69 #if CDS_COMPILER != CDS_COMPILER_MSVC
70 template<> CDS_EXPORT_API singleton_vtbl * sh_singleton_instance< signal_buffered_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 );
121 # undef CDS_SH_RCU_DECLARE_THREAD_GC
123 template <class RCUtag>
124 class sh_singleton: public singleton_vtbl
127 typedef RCUtag rcu_tag;
128 typedef cds::urcu::details::thread_gc< rcu_tag > thread_gc;
131 typedef typename thread_gc::thread_record thread_record;
132 typedef sh_singleton_instance< rcu_tag > rcu_instance;
135 atomics::atomic<uint32_t> m_nGlobalControl;
136 thread_list< rcu_tag > m_ThreadList;
140 sh_singleton( int nSignal )
141 : m_nGlobalControl(1)
142 , m_nSigNo( nSignal )
144 set_signal_handler();
149 clear_signal_handler();
153 static sh_singleton * instance()
155 return static_cast< sh_singleton *>( rcu_instance::s_pRCU );
160 return rcu_instance::s_pRCU != nullptr;
163 int signal_no() const
169 virtual void retire_ptr( retired_ptr& p ) = 0;
171 public: // thread_gc interface
172 thread_record * attach_thread()
174 return m_ThreadList.alloc();
177 void detach_thread( thread_record * pRec )
179 m_ThreadList.retire( pRec );
182 uint32_t global_control_word( atomics::memory_order mo ) const
184 return m_nGlobalControl.load( mo );
188 void set_signal_handler();
189 void clear_signal_handler();
190 static void signal_handler( int signo, siginfo_t * sigInfo, void * context );
191 void raise_signal( cds::OS::ThreadId tid );
193 template <class Backoff>
194 void force_membar_all_threads( Backoff& bkOff );
196 void switch_next_epoch()
198 m_nGlobalControl.fetch_xor( rcu_tag::c_nControlBit, atomics::memory_order_seq_cst );
200 bool check_grace_period( thread_record * pRec ) const;
202 template <class Backoff>
203 void wait_for_quiescent_state( Backoff& bkOff );
206 # define CDS_SIGRCU_DECLARE_SINGLETON( tag_ ) \
207 template <> class singleton< tag_ > { \
209 typedef tag_ rcu_tag ; \
210 typedef cds::urcu::details::thread_gc< rcu_tag > thread_gc ; \
212 typedef thread_gc::thread_record thread_record ; \
213 typedef sh_singleton_instance< rcu_tag > rcu_instance ; \
214 typedef sh_singleton< rcu_tag > rcu_singleton ; \
216 static bool isUsed() { return rcu_singleton::isUsed() ; } \
217 static rcu_singleton * instance() { assert( rcu_instance::s_pRCU ); return static_cast<rcu_singleton *>( rcu_instance::s_pRCU ); } \
218 static thread_record * attach_thread() { return instance()->attach_thread() ; } \
219 static void detach_thread( thread_record * pRec ) { return instance()->detach_thread( pRec ) ; } \
220 static uint32_t global_control_word( atomics::memory_order mo ) { return instance()->global_control_word( mo ) ; } \
223 CDS_SIGRCU_DECLARE_SINGLETON( signal_buffered_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