Removed trailing spaces
[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-2016
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         ~thread_data() {} \
55     }
56
57     CDS_SHURCU_DECLARE_THREAD_DATA( signal_buffered_tag );
58     CDS_SHURCU_DECLARE_THREAD_DATA( signal_threaded_tag );
59
60 #   undef CDS_SHURCU_DECLARE_THREAD_DATA
61
62     template <typename RCUtag>
63     struct sh_singleton_instance
64     {
65         static CDS_EXPORT_API singleton_vtbl *     s_pRCU;
66     };
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;
70 #endif
71
72     template <typename SigRCUtag>
73     class sh_thread_gc
74     {
75     public:
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;
80
81     protected:
82         static thread_record * get_thread_record();
83
84     public:
85         sh_thread_gc();
86         ~sh_thread_gc();
87     public:
88         static void access_lock();
89         static void access_unlock();
90         static bool is_locked();
91
92         /// Retire pointer \p by the disposer \p Disposer
93         template <typename Disposer, typename T>
94         static void retire( T * p )
95         {
96             retire( p, cds::details::static_functor<Disposer, T>::call );
97         }
98
99         /// Retire pointer \p by the disposer \p pFunc
100         template <typename T>
101         static void retire( T * p, void (* pFunc)(T *) )
102         {
103             retired_ptr rp( reinterpret_cast<void *>( p ), reinterpret_cast<free_retired_ptr_func>( pFunc ) );
104             retire( rp );
105         }
106
107         /// Retire pointer \p
108         static void retire( retired_ptr& p )
109         {
110             assert( sh_singleton_instance< rcu_tag >::s_pRCU );
111             sh_singleton_instance< rcu_tag >::s_pRCU->retire_ptr( p );
112         }
113     };
114
115 #   define CDS_SH_RCU_DECLARE_THREAD_GC( tag_ ) template <> class thread_gc<tag_>: public sh_thread_gc<tag_> {}
116
117     CDS_SH_RCU_DECLARE_THREAD_GC( signal_buffered_tag  );
118     CDS_SH_RCU_DECLARE_THREAD_GC( signal_threaded_tag );
119
120 #   undef CDS_SH_RCU_DECLARE_THREAD_GC
121
122     template <class RCUtag>
123     class sh_singleton: public singleton_vtbl
124     {
125     public:
126         typedef RCUtag  rcu_tag;
127         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc;
128
129     protected:
130         typedef typename thread_gc::thread_record   thread_record;
131         typedef sh_singleton_instance< rcu_tag >    rcu_instance;
132
133     protected:
134         atomics::atomic<uint32_t>    m_nGlobalControl;
135         thread_list< rcu_tag >          m_ThreadList;
136         int const                       m_nSigNo;
137
138     protected:
139         sh_singleton( int nSignal )
140             : m_nGlobalControl(1)
141             , m_nSigNo( nSignal )
142         {
143             set_signal_handler();
144         }
145
146         ~sh_singleton()
147         {
148             clear_signal_handler();
149         }
150
151     public:
152         static sh_singleton * instance()
153         {
154             return static_cast< sh_singleton *>( rcu_instance::s_pRCU );
155         }
156
157         static bool isUsed()
158         {
159             return rcu_instance::s_pRCU != nullptr;
160         }
161
162         int signal_no() const
163         {
164             return m_nSigNo;
165         }
166
167     public:
168         virtual void retire_ptr( retired_ptr& p ) = 0;
169
170     public: // thread_gc interface
171         thread_record * attach_thread()
172         {
173             return m_ThreadList.alloc();
174         }
175
176         void detach_thread( thread_record * pRec )
177         {
178             m_ThreadList.retire( pRec );
179         }
180
181         uint32_t global_control_word( atomics::memory_order mo ) const
182         {
183             return m_nGlobalControl.load( mo );
184         }
185
186     protected:
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 );
191
192         template <class Backoff>
193         void force_membar_all_threads( Backoff& bkOff );
194
195         void switch_next_epoch()
196         {
197             m_nGlobalControl.fetch_xor( rcu_tag::c_nControlBit, atomics::memory_order_seq_cst );
198         }
199         bool check_grace_period( thread_record * pRec ) const;
200
201         template <class Backoff>
202         void wait_for_quiescent_state( Backoff& bkOff );
203     };
204
205 #   define CDS_SIGRCU_DECLARE_SINGLETON( tag_ ) \
206     template <> class singleton< tag_ > { \
207     public: \
208         typedef tag_  rcu_tag ; \
209         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc ; \
210     protected: \
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 ; \
214     public: \
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 ) ; } \
220     }
221
222     CDS_SIGRCU_DECLARE_SINGLETON( signal_buffered_tag  );
223     CDS_SIGRCU_DECLARE_SINGLETON( signal_threaded_tag );
224
225 #   undef CDS_SIGRCU_DECLARE_SINGLETON
226
227 }}} // namespace cds::urcu::details
228 //@endcond
229
230 #endif // #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
231 #endif // #ifndef CDSLIB_URCU_DETAILS_SH_DECL_H