[TSan] Fixed data race: added compiler barriers, tuned memory ordering
[libcds.git] / cds / urcu / details / gp_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_GP_DECL_H
32 #define CDSLIB_URCU_DETAILS_GP_DECL_H
33
34 #include <cds/urcu/details/base.h>
35 #include <cds/details/static_functor.h>
36 #include <cds/details/lib.h>
37
38 //@cond
39 namespace cds { namespace urcu { namespace details {
40
41     // We could derive thread_data from thread_list_record
42     // but in this case m_nAccessControl would have offset != 0
43     // that is not so efficiently
44 #   define CDS_GPURCU_DECLARE_THREAD_DATA(tag_) \
45     template <> struct thread_data<tag_> { \
46         atomics::atomic<uint32_t>        m_nAccessControl ; \
47         thread_list_record< thread_data >   m_list ; \
48         thread_data(): m_nAccessControl(0) {} \
49         explicit thread_data( OS::ThreadId owner ): m_nAccessControl(0), m_list(owner) {} \
50         ~thread_data() {} \
51     }
52
53     CDS_GPURCU_DECLARE_THREAD_DATA( general_instant_tag );
54     CDS_GPURCU_DECLARE_THREAD_DATA( general_buffered_tag );
55     CDS_GPURCU_DECLARE_THREAD_DATA( general_threaded_tag );
56
57 #   undef CDS_GPURCU_DECLARE_THREAD_DATA
58
59     template <typename RCUtag>
60     struct gp_singleton_instance
61     {
62         static CDS_EXPORT_API singleton_vtbl *     s_pRCU;
63     };
64 #if !( CDS_COMPILER == CDS_COMPILER_MSVC || (CDS_COMPILER == CDS_COMPILER_INTEL && CDS_OS_INTERFACE == CDS_OSI_WINDOWS))
65     template<> CDS_EXPORT_API singleton_vtbl * gp_singleton_instance< general_instant_tag >::s_pRCU;
66     template<> CDS_EXPORT_API singleton_vtbl * gp_singleton_instance< general_buffered_tag >::s_pRCU;
67     template<> CDS_EXPORT_API singleton_vtbl * gp_singleton_instance< general_threaded_tag >::s_pRCU;
68 #endif
69
70     template <typename GPRCUtag>
71     class gp_thread_gc
72     {
73     public:
74         typedef GPRCUtag                    rcu_tag;
75         typedef typename rcu_tag::rcu_class rcu_class;
76         typedef thread_data< rcu_tag >      thread_record;
77         typedef cds::urcu::details::scoped_lock< gp_thread_gc > scoped_lock;
78
79     protected:
80         static thread_record * get_thread_record();
81
82     public:
83         gp_thread_gc();
84         ~gp_thread_gc();
85     public:
86         static void access_lock();
87         static void access_unlock();
88         static bool is_locked();
89
90         /// Retire pointer \p by the disposer \p Disposer
91         template <typename Disposer, typename T>
92         static void retire( T * p )
93         {
94             retire( p, cds::details::static_functor<Disposer, T>::call );
95         }
96
97         /// Retire pointer \p by the disposer \p pFunc
98         template <typename T>
99         static void retire( T * p, void (* pFunc)(T *))
100         {
101             retired_ptr rp( reinterpret_cast<void *>( p ), reinterpret_cast<free_retired_ptr_func>( pFunc ));
102             retire( rp );
103         }
104
105         /// Retire pointer \p
106         static void retire( retired_ptr& p )
107         {
108             assert( gp_singleton_instance< rcu_tag >::s_pRCU );
109             gp_singleton_instance< rcu_tag >::s_pRCU->retire_ptr( p );
110         }
111     };
112
113 #   define CDS_GP_RCU_DECLARE_THREAD_GC( tag_ ) template <> class thread_gc<tag_>: public gp_thread_gc<tag_> {}
114
115     CDS_GP_RCU_DECLARE_THREAD_GC( general_instant_tag  );
116     CDS_GP_RCU_DECLARE_THREAD_GC( general_buffered_tag );
117     CDS_GP_RCU_DECLARE_THREAD_GC( general_threaded_tag );
118
119 #   undef CDS_GP_RCU_DECLARE_THREAD_GC
120
121     template <class RCUtag>
122     class gp_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 gp_singleton_instance< rcu_tag >    rcu_instance;
131
132     protected:
133         atomics::atomic<uint32_t>    m_nGlobalControl;
134         thread_list< rcu_tag >          m_ThreadList;
135
136     protected:
137         gp_singleton()
138             : m_nGlobalControl(1)
139         {}
140
141         ~gp_singleton()
142         {}
143
144     public:
145         static gp_singleton * instance()
146         {
147             return static_cast< gp_singleton *>( rcu_instance::s_pRCU );
148         }
149
150         static bool isUsed()
151         {
152             return rcu_instance::s_pRCU != nullptr;
153         }
154
155     public:
156         virtual void retire_ptr( retired_ptr& p ) = 0;
157
158     public: // thread_gc interface
159         thread_record * attach_thread()
160         {
161             return m_ThreadList.alloc();
162         }
163
164         void detach_thread( thread_record * pRec )
165         {
166             m_ThreadList.retire( pRec );
167         }
168
169         uint32_t global_control_word( atomics::memory_order mo ) const
170         {
171             return m_nGlobalControl.load( mo );
172         }
173
174     protected:
175         bool check_grace_period( thread_record * pRec ) const;
176
177         template <class Backoff>
178         void flip_and_wait( Backoff& bkoff );
179     };
180
181 #   define CDS_GP_RCU_DECLARE_SINGLETON( tag_ ) \
182     template <> class singleton< tag_ > { \
183     public: \
184         typedef tag_  rcu_tag ; \
185         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc ; \
186     protected: \
187         typedef thread_gc::thread_record            thread_record ; \
188         typedef gp_singleton_instance< rcu_tag >    rcu_instance  ; \
189         typedef gp_singleton< rcu_tag >             rcu_singleton ; \
190     public: \
191         static bool isUsed() { return rcu_singleton::isUsed() ; } \
192         static rcu_singleton * instance() { assert( rcu_instance::s_pRCU ); return static_cast<rcu_singleton *>( rcu_instance::s_pRCU ); } \
193         static thread_record * attach_thread() { return instance()->attach_thread() ; } \
194         static void detach_thread( thread_record * pRec ) { return instance()->detach_thread( pRec ) ; } \
195         static uint32_t global_control_word( atomics::memory_order mo ) { return instance()->global_control_word( mo ) ; } \
196     }
197
198     CDS_GP_RCU_DECLARE_SINGLETON( general_instant_tag  );
199     CDS_GP_RCU_DECLARE_SINGLETON( general_buffered_tag );
200     CDS_GP_RCU_DECLARE_SINGLETON( general_threaded_tag );
201
202 #   undef CDS_GP_RCU_DECLARE_SINGLETON
203
204 }}} // namespace cds::urcu::details
205 //@endcond
206
207 #endif // #ifndef CDSLIB_URCU_DETAILS_GP_DECL_H