Removed signal_threaded uRCU
[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
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 #endif
70
71     template <typename SigRCUtag>
72     class sh_thread_gc
73     {
74     public:
75         typedef SigRCUtag                   rcu_tag;
76         typedef typename rcu_tag::rcu_class rcu_class;
77         typedef thread_data< rcu_tag >      thread_record;
78         typedef cds::urcu::details::scoped_lock< sh_thread_gc > scoped_lock;
79
80     protected:
81         static thread_record * get_thread_record();
82
83     public:
84         sh_thread_gc();
85         ~sh_thread_gc();
86
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
119 #   undef CDS_SH_RCU_DECLARE_THREAD_GC
120
121     template <class RCUtag>
122     class sh_singleton: public singleton_vtbl
123     {
124     public:
125         typedef RCUtag  rcu_tag;
126         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc;
127
128     protected:
129         typedef typename thread_gc::thread_record   thread_record;
130         typedef sh_singleton_instance< rcu_tag >    rcu_instance;
131
132     protected:
133         atomics::atomic<uint32_t>   m_nGlobalControl;
134         thread_list< rcu_tag >      m_ThreadList;
135         int const                   m_nSigNo;
136
137     protected:
138         sh_singleton( int nSignal )
139             : m_nGlobalControl(1)
140             , m_nSigNo( nSignal )
141         {
142             set_signal_handler();
143         }
144
145         ~sh_singleton()
146         {
147             clear_signal_handler();
148         }
149
150     public:
151         static sh_singleton * instance()
152         {
153             return static_cast< sh_singleton *>( rcu_instance::s_pRCU );
154         }
155
156         static bool isUsed()
157         {
158             return rcu_instance::s_pRCU != nullptr;
159         }
160
161         int signal_no() const
162         {
163             return m_nSigNo;
164         }
165
166     public:
167         virtual void retire_ptr( retired_ptr& p ) = 0;
168
169     public: // thread_gc interface
170         thread_record * attach_thread()
171         {
172             return m_ThreadList.alloc();
173         }
174
175         void detach_thread( thread_record * pRec )
176         {
177             m_ThreadList.retire( pRec );
178         }
179
180         uint32_t global_control_word( atomics::memory_order mo ) const
181         {
182             return m_nGlobalControl.load( mo );
183         }
184
185     protected:
186         void set_signal_handler();
187         void clear_signal_handler();
188         static void signal_handler( int signo, siginfo_t * sigInfo, void * context );
189         void raise_signal( cds::OS::ThreadId tid );
190
191         template <class Backoff>
192         void force_membar_all_threads( Backoff& bkOff );
193
194         void switch_next_epoch()
195         {
196             m_nGlobalControl.fetch_xor( rcu_tag::c_nControlBit, atomics::memory_order_seq_cst );
197         }
198         bool check_grace_period( thread_record * pRec ) const;
199
200         template <class Backoff>
201         void wait_for_quiescent_state( Backoff& bkOff );
202     };
203
204 #   define CDS_SIGRCU_DECLARE_SINGLETON( tag_ ) \
205     template <> class singleton< tag_ > { \
206     public: \
207         typedef tag_  rcu_tag ; \
208         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc ; \
209     protected: \
210         typedef thread_gc::thread_record            thread_record ; \
211         typedef sh_singleton_instance< rcu_tag >    rcu_instance  ; \
212         typedef sh_singleton< rcu_tag >             rcu_singleton ; \
213     public: \
214         static bool isUsed() { return rcu_singleton::isUsed() ; } \
215         static rcu_singleton * instance() { assert( rcu_instance::s_pRCU ); return static_cast<rcu_singleton *>( rcu_instance::s_pRCU ); } \
216         static thread_record * attach_thread() { return instance()->attach_thread() ; } \
217         static void detach_thread( thread_record * pRec ) { return instance()->detach_thread( pRec ) ; } \
218         static uint32_t global_control_word( atomics::memory_order mo ) { return instance()->global_control_word( mo ) ; } \
219     }
220
221     CDS_SIGRCU_DECLARE_SINGLETON( signal_buffered_tag  );
222
223 #   undef CDS_SIGRCU_DECLARE_SINGLETON
224
225 }}} // namespace cds::urcu::details
226 //@endcond
227
228 #endif // #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
229 #endif // #ifndef CDSLIB_URCU_DETAILS_SH_DECL_H