Uses different pass count for different parallel queue test cases
[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 #include <cds/user_setup/cache_line.h>
40
41 #include <signal.h>
42
43 //@cond
44 namespace cds { namespace urcu { namespace details {
45
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) {} \
57         ~thread_data() {} \
58     }
59
60     CDS_SHURCU_DECLARE_THREAD_DATA( signal_buffered_tag );
61
62 #   undef CDS_SHURCU_DECLARE_THREAD_DATA
63
64     template <typename RCUtag>
65     struct sh_singleton_instance
66     {
67         static CDS_EXPORT_API singleton_vtbl *     s_pRCU;
68     };
69 #if CDS_COMPILER != CDS_COMPILER_MSVC
70     template<> CDS_EXPORT_API singleton_vtbl * sh_singleton_instance< signal_buffered_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
121 #   undef CDS_SH_RCU_DECLARE_THREAD_GC
122
123     template <class RCUtag>
124     class sh_singleton: public singleton_vtbl
125     {
126     public:
127         typedef RCUtag  rcu_tag;
128         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc;
129
130     protected:
131         typedef typename thread_gc::thread_record   thread_record;
132         typedef sh_singleton_instance< rcu_tag >    rcu_instance;
133
134     protected:
135         atomics::atomic<uint32_t>   m_nGlobalControl;
136         thread_list< rcu_tag >      m_ThreadList;
137         int const                   m_nSigNo;
138
139     protected:
140         sh_singleton( int nSignal )
141             : m_nGlobalControl(1)
142             , m_nSigNo( nSignal )
143         {
144             set_signal_handler();
145         }
146
147         ~sh_singleton()
148         {
149             clear_signal_handler();
150         }
151
152     public:
153         static sh_singleton * instance()
154         {
155             return static_cast< sh_singleton *>( rcu_instance::s_pRCU );
156         }
157
158         static bool isUsed()
159         {
160             return rcu_instance::s_pRCU != nullptr;
161         }
162
163         int signal_no() const
164         {
165             return m_nSigNo;
166         }
167
168     public:
169         virtual void retire_ptr( retired_ptr& p ) = 0;
170
171     public: // thread_gc interface
172         thread_record * attach_thread()
173         {
174             return m_ThreadList.alloc();
175         }
176
177         void detach_thread( thread_record * pRec )
178         {
179             m_ThreadList.retire( pRec );
180         }
181
182         uint32_t global_control_word( atomics::memory_order mo ) const
183         {
184             return m_nGlobalControl.load( mo );
185         }
186
187     protected:
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 );
192
193         template <class Backoff>
194         void force_membar_all_threads( Backoff& bkOff );
195
196         void switch_next_epoch()
197         {
198             m_nGlobalControl.fetch_xor( rcu_tag::c_nControlBit, atomics::memory_order_seq_cst );
199         }
200         bool check_grace_period( thread_record * pRec ) const;
201
202         template <class Backoff>
203         void wait_for_quiescent_state( Backoff& bkOff );
204     };
205
206 #   define CDS_SIGRCU_DECLARE_SINGLETON( tag_ ) \
207     template <> class singleton< tag_ > { \
208     public: \
209         typedef tag_  rcu_tag ; \
210         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc ; \
211     protected: \
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 ; \
215     public: \
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 ) ; } \
221     }
222
223     CDS_SIGRCU_DECLARE_SINGLETON( signal_buffered_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