b87c4b1ecd2db1d446f2979d819442ae9ad8f00d
[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         ~thread_data() {} \
50     }
51
52     CDS_GPURCU_DECLARE_THREAD_DATA( general_instant_tag );
53     CDS_GPURCU_DECLARE_THREAD_DATA( general_buffered_tag );
54     CDS_GPURCU_DECLARE_THREAD_DATA( general_threaded_tag );
55
56 #   undef CDS_GPURCU_DECLARE_THREAD_DATA
57
58     template <typename RCUtag>
59     struct gp_singleton_instance
60     {
61         static CDS_EXPORT_API singleton_vtbl *     s_pRCU;
62     };
63 #if !( CDS_COMPILER == CDS_COMPILER_MSVC || (CDS_COMPILER == CDS_COMPILER_INTEL && CDS_OS_INTERFACE == CDS_OSI_WINDOWS))
64     template<> CDS_EXPORT_API singleton_vtbl * gp_singleton_instance< general_instant_tag >::s_pRCU;
65     template<> CDS_EXPORT_API singleton_vtbl * gp_singleton_instance< general_buffered_tag >::s_pRCU;
66     template<> CDS_EXPORT_API singleton_vtbl * gp_singleton_instance< general_threaded_tag >::s_pRCU;
67 #endif
68
69     template <typename GPRCUtag>
70     class gp_thread_gc
71     {
72     public:
73         typedef GPRCUtag                    rcu_tag;
74         typedef typename rcu_tag::rcu_class rcu_class;
75         typedef thread_data< rcu_tag >      thread_record;
76         typedef cds::urcu::details::scoped_lock< gp_thread_gc > scoped_lock;
77
78     protected:
79         static thread_record * get_thread_record();
80
81     public:
82         gp_thread_gc();
83         ~gp_thread_gc();
84     public:
85         static void access_lock();
86         static void access_unlock();
87         static bool is_locked();
88
89         /// Retire pointer \p by the disposer \p Disposer
90         template <typename Disposer, typename T>
91         static void retire( T * p )
92         {
93             retire( p, cds::details::static_functor<Disposer, T>::call );
94         }
95
96         /// Retire pointer \p by the disposer \p pFunc
97         template <typename T>
98         static void retire( T * p, void (* pFunc)(T *) )
99         {
100             retired_ptr rp( reinterpret_cast<void *>( p ), reinterpret_cast<free_retired_ptr_func>( pFunc ) );
101             retire( rp );
102         }
103
104         /// Retire pointer \p
105         static void retire( retired_ptr& p )
106         {
107             assert( gp_singleton_instance< rcu_tag >::s_pRCU );
108             gp_singleton_instance< rcu_tag >::s_pRCU->retire_ptr( p );
109         }
110     };
111
112 #   define CDS_GP_RCU_DECLARE_THREAD_GC( tag_ ) template <> class thread_gc<tag_>: public gp_thread_gc<tag_> {}
113
114     CDS_GP_RCU_DECLARE_THREAD_GC( general_instant_tag  );
115     CDS_GP_RCU_DECLARE_THREAD_GC( general_buffered_tag );
116     CDS_GP_RCU_DECLARE_THREAD_GC( general_threaded_tag );
117
118 #   undef CDS_GP_RCU_DECLARE_THREAD_GC
119
120     template <class RCUtag>
121     class gp_singleton: public singleton_vtbl
122     {
123     public:
124         typedef RCUtag  rcu_tag;
125         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc;
126
127     protected:
128         typedef typename thread_gc::thread_record   thread_record;
129         typedef gp_singleton_instance< rcu_tag >    rcu_instance;
130
131     protected:
132         atomics::atomic<uint32_t>    m_nGlobalControl;
133         thread_list< rcu_tag >          m_ThreadList;
134
135     protected:
136         gp_singleton()
137             : m_nGlobalControl(1)
138         {}
139
140         ~gp_singleton()
141         {}
142
143     public:
144         static gp_singleton * instance()
145         {
146             return static_cast< gp_singleton *>( rcu_instance::s_pRCU );
147         }
148
149         static bool isUsed()
150         {
151             return rcu_instance::s_pRCU != nullptr;
152         }
153
154     public:
155         virtual void retire_ptr( retired_ptr& p ) = 0;
156
157     public: // thread_gc interface
158         thread_record * attach_thread()
159         {
160             return m_ThreadList.alloc();
161         }
162
163         void detach_thread( thread_record * pRec )
164         {
165             m_ThreadList.retire( pRec );
166         }
167
168         uint32_t global_control_word( atomics::memory_order mo ) const
169         {
170             return m_nGlobalControl.load( mo );
171         }
172
173     protected:
174         bool check_grace_period( thread_record * pRec ) const;
175
176         template <class Backoff>
177         void flip_and_wait( Backoff& bkoff );
178     };
179
180 #   define CDS_GP_RCU_DECLARE_SINGLETON( tag_ ) \
181     template <> class singleton< tag_ > { \
182     public: \
183         typedef tag_  rcu_tag ; \
184         typedef cds::urcu::details::thread_gc< rcu_tag >   thread_gc ; \
185     protected: \
186         typedef thread_gc::thread_record            thread_record ; \
187         typedef gp_singleton_instance< rcu_tag >    rcu_instance  ; \
188         typedef gp_singleton< rcu_tag >             rcu_singleton ; \
189     public: \
190         static bool isUsed() { return rcu_singleton::isUsed() ; } \
191         static rcu_singleton * instance() { assert( rcu_instance::s_pRCU ); return static_cast<rcu_singleton *>( rcu_instance::s_pRCU ); } \
192         static thread_record * attach_thread() { return instance()->attach_thread() ; } \
193         static void detach_thread( thread_record * pRec ) { return instance()->detach_thread( pRec ) ; } \
194         static uint32_t global_control_word( atomics::memory_order mo ) { return instance()->global_control_word( mo ) ; } \
195     }
196
197     CDS_GP_RCU_DECLARE_SINGLETON( general_instant_tag  );
198     CDS_GP_RCU_DECLARE_SINGLETON( general_buffered_tag );
199     CDS_GP_RCU_DECLARE_SINGLETON( general_threaded_tag );
200
201 #   undef CDS_GP_RCU_DECLARE_SINGLETON
202
203 }}} // namespace cds::urcu::details
204 //@endcond
205
206 #endif // #ifndef CDSLIB_URCU_DETAILS_GP_DECL_H