f0fe6ad3cc69dc43a066a89a35dbf9e392cb0b48
[libcds.git] / cds / urcu / details / sh_decl.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
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.
18
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.
29 */
30
31 #ifndef CDSLIB_URCU_DETAILS_SH_DECL_H
32 #define CDSLIB_URCU_DETAILS_SH_DECL_H
33
34 #include <cds/urcu/details/base.h>
35
36 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
37 #include <cds/details/static_functor.h>
38 #include <cds/details/lib.h>
39
40 #include <signal.h>
41
42 //@cond
43 namespace cds { namespace urcu { namespace details {
44
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) {} \
55         ~thread_data() {} \
56     }
57
58     CDS_SHURCU_DECLARE_THREAD_DATA( signal_buffered_tag );
59     CDS_SHURCU_DECLARE_THREAD_DATA( signal_threaded_tag );
60
61 #   undef CDS_SHURCU_DECLARE_THREAD_DATA
62
63     template <typename RCUtag>
64     struct sh_singleton_instance
65     {
66         static CDS_EXPORT_API singleton_vtbl *     s_pRCU;
67     };
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;
71 #endif
72
73     template <typename SigRCUtag>
74     class sh_thread_gc
75     {
76     public:
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;
81
82     protected:
83         static thread_record * get_thread_record();
84
85     public:
86         sh_thread_gc();
87         ~sh_thread_gc();
88
89     public:
90         static void access_lock();
91         static void access_unlock();
92         static bool is_locked();
93
94         /// Retire pointer \p by the disposer \p Disposer
95         template <typename Disposer, typename T>
96         static void retire( T * p )
97         {
98             retire( p, cds::details::static_functor<Disposer, T>::call );
99         }
100
101         /// Retire pointer \p by the disposer \p pFunc
102         template <typename T>
103         static void retire( T * p, void (* pFunc)(T *))
104         {
105             retired_ptr rp( reinterpret_cast<void *>( p ), reinterpret_cast<free_retired_ptr_func>( pFunc ));
106             retire( rp );
107         }
108
109         /// Retire pointer \p
110         static void retire( retired_ptr& p )
111         {
112             assert( sh_singleton_instance< rcu_tag >::s_pRCU );
113             sh_singleton_instance< rcu_tag >::s_pRCU->retire_ptr( p );
114         }
115     };
116
117 #   define CDS_SH_RCU_DECLARE_THREAD_GC( tag_ ) template <> class thread_gc<tag_>: public sh_thread_gc<tag_> {}
118
119     CDS_SH_RCU_DECLARE_THREAD_GC( signal_buffered_tag  );
120     CDS_SH_RCU_DECLARE_THREAD_GC( signal_threaded_tag );
121
122 #   undef CDS_SH_RCU_DECLARE_THREAD_GC
123
124     template <class RCUtag>
125     class sh_singleton: public singleton_vtbl
126     {
127     public:
128         typedef RCUtag  rcu_tag;
129         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc;
130
131     protected:
132         typedef typename thread_gc::thread_record   thread_record;
133         typedef sh_singleton_instance< rcu_tag >    rcu_instance;
134
135     protected:
136         atomics::atomic<uint32_t>   m_nGlobalControl;
137         thread_list< rcu_tag >      m_ThreadList;
138         int const                   m_nSigNo;
139
140     protected:
141         sh_singleton( int nSignal )
142             : m_nGlobalControl(1)
143             , m_nSigNo( nSignal )
144         {
145             set_signal_handler();
146         }
147
148         ~sh_singleton()
149         {
150             clear_signal_handler();
151         }
152
153     public:
154         static sh_singleton * instance()
155         {
156             return static_cast< sh_singleton *>( rcu_instance::s_pRCU );
157         }
158
159         static bool isUsed()
160         {
161             return rcu_instance::s_pRCU != nullptr;
162         }
163
164         int signal_no() const
165         {
166             return m_nSigNo;
167         }
168
169     public:
170         virtual void retire_ptr( retired_ptr& p ) = 0;
171
172     public: // thread_gc interface
173         thread_record * attach_thread()
174         {
175             return m_ThreadList.alloc();
176         }
177
178         void detach_thread( thread_record * pRec )
179         {
180             m_ThreadList.retire( pRec );
181         }
182
183         uint32_t global_control_word( atomics::memory_order mo ) const
184         {
185             return m_nGlobalControl.load( mo );
186         }
187
188     protected:
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 );
193
194         template <class Backoff>
195         void force_membar_all_threads( Backoff& bkOff );
196
197         void switch_next_epoch()
198         {
199             m_nGlobalControl.fetch_xor( rcu_tag::c_nControlBit, atomics::memory_order_seq_cst );
200         }
201         bool check_grace_period( thread_record * pRec ) const;
202
203         template <class Backoff>
204         void wait_for_quiescent_state( Backoff& bkOff );
205     };
206
207 #   define CDS_SIGRCU_DECLARE_SINGLETON( tag_ ) \
208     template <> class singleton< tag_ > { \
209     public: \
210         typedef tag_  rcu_tag ; \
211         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc ; \
212     protected: \
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 ; \
216     public: \
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 ) ; } \
222     }
223
224     CDS_SIGRCU_DECLARE_SINGLETON( signal_buffered_tag  );
225     CDS_SIGRCU_DECLARE_SINGLETON( signal_threaded_tag );
226
227 #   undef CDS_SIGRCU_DECLARE_SINGLETON
228
229 }}} // namespace cds::urcu::details
230 //@endcond
231
232 #endif // #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
233 #endif // #ifndef CDSLIB_URCU_DETAILS_SH_DECL_H