1386e6061aea904e11b1d389e7e4a918b16072b0
[libcds.git] / cds / urcu / details / sh_decl.h
1 //$$CDS-header$$
2
3 #ifndef _CDS_URCU_DETAILS_SH_DECL_H
4 #define _CDS_URCU_DETAILS_SH_DECL_H
5
6 #include <cds/urcu/details/base.h>
7
8 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
9 #include <cds/details/static_functor.h>
10 #include <cds/details/lib.h>
11
12 #include <signal.h>
13
14 //@cond
15 namespace cds { namespace urcu { namespace details {
16
17     // We could derive thread_data from thread_list_record
18     // but in this case m_nAccessControl would have offset != 0
19     // that is not so efficiently
20 #   define CDS_SHURCU_DECLARE_THREAD_DATA(tag_) \
21     template <> struct thread_data<tag_> { \
22         CDS_ATOMIC::atomic<uint32_t>        m_nAccessControl ; \
23         CDS_ATOMIC::atomic<bool>            m_bNeedMemBar    ; \
24         thread_list_record< thread_data >   m_list ; \
25         thread_data(): m_nAccessControl(0), m_bNeedMemBar(false) {} \
26         ~thread_data() {} \
27     }
28
29     CDS_SHURCU_DECLARE_THREAD_DATA( signal_buffered_tag );
30     CDS_SHURCU_DECLARE_THREAD_DATA( signal_threaded_tag );
31
32 #   undef CDS_SHURCU_DECLARE_THREAD_DATA
33
34     template <typename RCUtag>
35     struct sh_singleton_instance
36     {
37         static CDS_EXPORT_API singleton_vtbl *     s_pRCU;
38     };
39 #if CDS_COMPILER != CDS_COMPILER_MSVC
40     template<> CDS_EXPORT_API singleton_vtbl * sh_singleton_instance< signal_buffered_tag >::s_pRCU;
41     template<> CDS_EXPORT_API singleton_vtbl * sh_singleton_instance< signal_threaded_tag >::s_pRCU;
42 #endif
43
44     template <typename SigRCUtag>
45     class sh_thread_gc
46     {
47     public:
48         typedef SigRCUtag                   rcu_tag;
49         typedef typename rcu_tag::rcu_class rcu_class;
50         typedef thread_data< rcu_tag >      thread_record;
51         typedef cds::urcu::details::scoped_lock< sh_thread_gc > scoped_lock;
52
53     protected:
54         static thread_record * get_thread_record();
55
56     public:
57         sh_thread_gc();
58         ~sh_thread_gc();
59     public:
60         static void access_lock();
61         static void access_unlock();
62         static bool is_locked();
63
64         /// Retire pointer \p by the disposer \p Disposer
65         template <typename Disposer, typename T>
66         static void retire( T * p )
67         {
68             retire( p, cds::details::static_functor<Disposer, T>::call );
69         }
70
71         /// Retire pointer \p by the disposer \p pFunc
72         template <typename T>
73         static void retire( T * p, void (* pFunc)(T *) )
74         {
75             retired_ptr rp( reinterpret_cast<void *>( p ), reinterpret_cast<free_retired_ptr_func>( pFunc ) );
76             retire( rp );
77         }
78
79         /// Retire pointer \p
80         static void retire( retired_ptr& p )
81         {
82             assert( sh_singleton_instance< rcu_tag >::s_pRCU );
83             sh_singleton_instance< rcu_tag >::s_pRCU->retire_ptr( p );
84         }
85     };
86
87 #   define CDS_SH_RCU_DECLARE_THREAD_GC( tag_ ) template <> class thread_gc<tag_>: public sh_thread_gc<tag_> {}
88
89     CDS_SH_RCU_DECLARE_THREAD_GC( signal_buffered_tag  );
90     CDS_SH_RCU_DECLARE_THREAD_GC( signal_threaded_tag );
91
92 #   undef CDS_SH_RCU_DECLARE_THREAD_GC
93
94     template <class RCUtag>
95     class sh_singleton: public singleton_vtbl
96     {
97     public:
98         typedef RCUtag  rcu_tag;
99         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc;
100
101     protected:
102         typedef typename thread_gc::thread_record   thread_record;
103         typedef sh_singleton_instance< rcu_tag >    rcu_instance;
104
105     protected:
106         CDS_ATOMIC::atomic<uint32_t>    m_nGlobalControl;
107         thread_list< rcu_tag >          m_ThreadList;
108         int const                       m_nSigNo;
109
110     protected:
111         sh_singleton( int nSignal )
112             : m_nGlobalControl(1)
113             , m_nSigNo( nSignal )
114         {
115             set_signal_handler();
116         }
117
118         ~sh_singleton()
119         {
120             clear_signal_handler();
121         }
122
123     public:
124         static sh_singleton * instance()
125         {
126             return static_cast< sh_singleton *>( rcu_instance::s_pRCU );
127         }
128
129         static bool isUsed()
130         {
131             return rcu_instance::s_pRCU != NULL;
132         }
133
134         int signal_no() const
135         {
136             return m_nSigNo;
137         }
138
139     public:
140         virtual void retire_ptr( retired_ptr& p ) = 0;
141
142     public: // thread_gc interface
143         thread_record * attach_thread()
144         {
145             return m_ThreadList.alloc();
146         }
147
148         void detach_thread( thread_record * pRec )
149         {
150             m_ThreadList.retire( pRec );
151         }
152
153         uint32_t global_control_word( CDS_ATOMIC::memory_order mo ) const
154         {
155             return m_nGlobalControl.load( mo );
156         }
157
158     protected:
159         void set_signal_handler();
160         void clear_signal_handler();
161         static void signal_handler( int signo, siginfo_t * sigInfo, void * context );
162         void raise_signal( cds::OS::ThreadId tid );
163
164         template <class Backoff>
165         void force_membar_all_threads( Backoff& bkOff );
166
167         void switch_next_epoch()
168         {
169             m_nGlobalControl.fetch_xor( rcu_tag::c_nControlBit, CDS_ATOMIC::memory_order_seq_cst );
170         }
171         bool check_grace_period( thread_record * pRec ) const;
172
173         template <class Backoff>
174         void wait_for_quiescent_state( Backoff& bkOff );
175     };
176
177 #   define CDS_SIGRCU_DECLARE_SINGLETON( tag_ ) \
178     template <> class singleton< tag_ > { \
179     public: \
180         typedef tag_  rcu_tag ; \
181         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc ; \
182     protected: \
183         typedef thread_gc::thread_record            thread_record ; \
184         typedef sh_singleton_instance< rcu_tag >    rcu_instance  ; \
185         typedef sh_singleton< rcu_tag >             rcu_singleton ; \
186     public: \
187         static bool isUsed() { return rcu_singleton::isUsed() ; } \
188         static rcu_singleton * instance() { assert( rcu_instance::s_pRCU ); return static_cast<rcu_singleton *>( rcu_instance::s_pRCU ); } \
189         static thread_record * attach_thread() { return instance()->attach_thread() ; } \
190         static void detach_thread( thread_record * pRec ) { return instance()->detach_thread( pRec ) ; } \
191         static uint32_t global_control_word( CDS_ATOMIC::memory_order mo ) { return instance()->global_control_word( mo ) ; } \
192     }
193
194     CDS_SIGRCU_DECLARE_SINGLETON( signal_buffered_tag  );
195     CDS_SIGRCU_DECLARE_SINGLETON( signal_threaded_tag );
196
197 #   undef CDS_SIGRCU_DECLARE_SINGLETON
198
199 }}} // namespace cds::urcu::details
200 //@endcond
201
202 #endif // #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
203 #endif // #ifndef _CDS_URCU_DETAILS_SH_DECL_H