rearrange cds/gc directory
[libcds.git] / cds / threading / details / _common.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_THREADING__COMMON_H
4 #define __CDS_THREADING__COMMON_H
5
6 #include <cds/gc/impl/hp_decl.h>
7 #include <cds/gc/impl/dhp_decl.h>
8
9 #include <cds/urcu/details/gp_decl.h>
10 #include <cds/urcu/details/sh_decl.h>
11 #include <cds/algo/elimination_tls.h>
12
13 namespace cds {
14     /// Threading support
15     /** \anchor cds_threading
16         The \p CDS library requires support from the threads.
17         Each garbage collector manages a control structure on the per-thread basis.
18         The library does not dictate any thread model. To embed the library to your application you should choose
19         appropriate implementation of \p cds::threading::Manager interface
20         or should provide yourself.
21         The \p %cds::threading::Manager interface manages \p ñds::threading::ThreadData structure that contains GC's thread specific data.
22
23         Any \p cds::threading::Manager implementation is a singleton and it must be accessible from any thread and from any point of
24         your application. Note that you should not mix different implementation of the \p cds::threading::Manager in your application.
25
26         Before compiling of your application you may define one of \p CDS_THREADING_xxx macro in cds/user_setup/threading.h file:
27             - \p CDS_THREADING_AUTODETECT - auto-detect appropriate threading model for your platform and compiler. This is
28                 predefined value of threading model in <tt>cds/user_setup/threading.h</tt>.
29             - \p CDS_THREADING_WIN_TLS - use <tt>cds::threading::wintls::Manager</tt> implementation based on Windows TLS API.
30                 Intended for Windows and Microsoft Visual C++ only. This is default threading model for Windows and MS Visual C++.
31             - \p CDS_THREADING_MSVC - use <tt>cds::threading::msvc::Manager</tt> implementation based on Microsoft Visual C++ <tt>__declspec(thread)</tt>
32                 declaration. Intended for Windows and Microsoft Visual C++ only.
33                 This macro should be explicitly specified if you want to use <tt>__declspec(thread)</tt> keyword.
34             - \p CDS_THREADING_PTHREAD - use <tt>cds::threading::pthread::Manager</tt> implementation based on pthread thread-specific
35                 data functions \p pthread_getspecific / \p pthread_setspecific. Intended for GCC and clang compilers.
36                 This is default threading model for GCC and clang.
37             - \p CDS_THREADING_GCC - use <tt>cds::threading::gcc::Manager</tt> implementation based on GCC \p __thread
38                 keyword. Intended for GCC compiler only. Note, that GCC compiler supports \p __thread keyword properly
39                 not for all platforms and even not for all GCC version.
40                 This macro should be explicitly specified if you want to use \p __thread keyword.
41             - \p CDS_THREADING_CXX11 - use <tt>cds::threading::cxx11::Manager</tt> implementation based on \p thread_local
42                 keyword introduced in C++11 standard. May be used only if your compiler supports C++11 thread-local storage.
43             - \p CDS_THREADING_USER_DEFINED - use user-provided threading model.
44
45         These macros select appropriate implementation of \p cds::threading::Manager class. The child namespaces of cds::threading
46         provide suitable implementation and import it to cds::threading by using \p using directive (or by using inline namespace if the compiler
47         supports it). So, if you need to call threading manager functions directly you should refer to \p cds::threading::Manager class.
48
49         @note Usually, you should not use \p cds::threading::Manager instance directly.
50         You may specify \p CDS_THREADING_xxx macro when building, everything else will setup automatically when you initialize the library,
51         see \ref cds_how_to_use "How to use libcds".
52
53         The interface of \p cds::threading::Manager class is the following:
54         \code
55         class Manager {
56         public:
57             // Initialize manager (called by cds::Initialize() )
58             static void init();
59
60             // Terminate manager (called by cds::Terminate() )
61             static void fini();
62
63             // Checks whether current thread is attached to \p libcds feature or not.
64             static bool isThreadAttached();
65
66             // This method must be called in beginning of thread execution
67             // (called by ctor of GC thread object, for example, by ctor of cds::gc::HP::thread_gc)
68             static void attachThread();
69
70             // This method must be called in end of thread execution
71             // (called by dtor of GC thread object, for example, by dtor of cds::gc::HP::thread_gc)
72             static void detachThread();
73
74             // Get cds::gc::HP thread GC implementation for current thread
75             static gc::HP::thread_gc_impl&   getHZPGC();
76
77             // Get cds::gc::DHP thread GC implementation for current thread;
78             static gc::DHP::thread_gc_impl&   getDHPGC();
79         };
80         \endcode
81
82         The library's core (dynamic linked library) is free of usage of user-supplied \p cds::threading::Manager code.
83         \p cds::threading::Manager is necessary for header-only part of \p CDS library (for \ref cds::threading::getGC functions).
84
85
86         Each thread that uses \p libcds data structures should be attached to threading::Manager before using
87         lock-free data structs.
88         See \ref cds_how_to_use "How to use" section for details
89
90         <b>Note for Windows</b>
91
92         When you use Garbage Collectors (GC) provided by \p libcds in your dll that dynamically loaded by \p LoadLibrary then there is no way
93         to use \p __declspec(thread) declaration to support threading model for \p libcds. MSDN says:
94
95         \li If a DLL declares any nonlocal data or object as __declspec( thread ), it can cause a protection fault if dynamically loaded.
96             After the DLL is loaded with \p LoadLibrary, it causes system failure whenever the code references the nonlocal __declspec( thread ) data.
97             Because the global variable space for a thread is allocated at run time, the size of this space is based on a calculation of the requirements
98             of the application plus the requirements of all the DLLs that are statically linked. When you use \p LoadLibrary, there is no way to extend
99             this space to allow for the thread local variables declared with __declspec( thread ). Use the TLS APIs, such as TlsAlloc, in your
100             DLL to allocate TLS if the DLL might be loaded with LoadLibrary.
101
102         Thus, in case when \p libcds or a dll that depends on \p libcds is loaded dynamically by calling \p LoadLibrary explicitly,
103         you should not use \p CDS_THREADING_MSVC macro. Instead, you should build your dll projects with \p CDS_THREADING_WIN_TLS only.
104     */
105     namespace threading {
106
107         //@cond
108         /// Thread-specific data
109         struct ThreadData {
110
111             //@cond
112             char CDS_DATA_ALIGNMENT(8) m_hpManagerPlaceholder[sizeof(cds::gc::HP::thread_gc_impl)];   ///< Michael's Hazard Pointer GC placeholder
113             char CDS_DATA_ALIGNMENT(8) m_dhpManagerPlaceholder[sizeof(cds::gc::DHP::thread_gc_impl)]; ///< Dynamic Hazard Pointer GC placeholder
114
115             cds::urcu::details::thread_data< cds::urcu::general_instant_tag > *     m_pGPIRCU;
116             cds::urcu::details::thread_data< cds::urcu::general_buffered_tag > *    m_pGPBRCU;
117             cds::urcu::details::thread_data< cds::urcu::general_threaded_tag > *    m_pGPTRCU;
118 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
119             cds::urcu::details::thread_data< cds::urcu::signal_buffered_tag > *    m_pSHBRCU;
120             cds::urcu::details::thread_data< cds::urcu::signal_threaded_tag > *    m_pSHTRCU;
121 #endif
122
123             //@endcond
124
125             cds::gc::HP::thread_gc_impl  * m_hpManager     ;   ///< Michael's Hazard Pointer GC thread-specific data
126             cds::gc::DHP::thread_gc_impl * m_dhpManager    ;   ///< Dynamic Hazard Pointer GC thread-specific data
127
128             size_t  m_nFakeProcessorNumber  ;   ///< fake "current processor" number
129
130             //@cond
131             size_t  m_nAttachCount;
132             //@endcond
133
134             /// Per-thread elimination record
135             cds::algo::elimination::record   m_EliminationRec;
136
137             //@cond
138             static CDS_EXPORT_API atomics::atomic<size_t> s_nLastUsedProcNo;
139             static CDS_EXPORT_API size_t                     s_nProcCount;
140             //@endcond
141
142             //@cond
143             ThreadData()
144                 : m_pGPIRCU( nullptr )
145                 , m_pGPBRCU( nullptr )
146                 , m_pGPTRCU( nullptr )
147 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
148                 , m_pSHBRCU( nullptr )
149                 , m_pSHTRCU( nullptr )
150 #endif
151                 , m_nFakeProcessorNumber( s_nLastUsedProcNo.fetch_add(1, atomics::memory_order_relaxed) % s_nProcCount )
152                 , m_nAttachCount(0)
153             {
154                 if (cds::gc::HP::isUsed() )
155                     m_hpManager = new (m_hpManagerPlaceholder) cds::gc::HP::thread_gc_impl;
156                 else
157                     m_hpManager = nullptr;
158
159                 if ( cds::gc::DHP::isUsed() )
160                     m_dhpManager = new (m_dhpManagerPlaceholder) cds::gc::DHP::thread_gc_impl;
161                 else
162                     m_dhpManager = nullptr;
163             }
164
165             ~ThreadData()
166             {
167                 if ( m_hpManager ) {
168                     typedef cds::gc::HP::thread_gc_impl hp_thread_gc_impl;
169                     m_hpManager->~hp_thread_gc_impl();
170                     m_hpManager = nullptr;
171                 }
172
173                 if ( m_dhpManager ) {
174                     typedef cds::gc::DHP::thread_gc_impl dhp_thread_gc_impl;
175                     m_dhpManager->~dhp_thread_gc_impl();
176                     m_dhpManager = nullptr;
177                 }
178
179                 assert( m_pGPIRCU == nullptr );
180                 assert( m_pGPBRCU == nullptr );
181                 assert( m_pGPTRCU == nullptr );
182 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
183                 assert( m_pSHBRCU == nullptr );
184                 assert( m_pSHTRCU == nullptr );
185 #endif
186             }
187
188             void init()
189             {
190                 if ( m_nAttachCount++ == 0 ) {
191                     if ( cds::gc::HP::isUsed() )
192                         m_hpManager->init();
193                     if ( cds::gc::DHP::isUsed() )
194                         m_dhpManager->init();
195
196                     if ( cds::urcu::details::singleton<cds::urcu::general_instant_tag>::isUsed() )
197                         m_pGPIRCU = cds::urcu::details::singleton<cds::urcu::general_instant_tag>::attach_thread();
198                     if ( cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::isUsed() )
199                         m_pGPBRCU = cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::attach_thread();
200                     if ( cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::isUsed() )
201                         m_pGPTRCU = cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::attach_thread();
202 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
203                     if ( cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::isUsed() )
204                         m_pSHBRCU = cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::attach_thread();
205                     if ( cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::isUsed() )
206                         m_pSHTRCU = cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::attach_thread();
207 #endif
208                 }
209             }
210
211             bool fini()
212             {
213                 if ( --m_nAttachCount == 0 ) {
214                     if ( cds::gc::DHP::isUsed() )
215                         m_dhpManager->fini();
216                     if ( cds::gc::HP::isUsed() )
217                         m_hpManager->fini();
218
219                     if ( cds::urcu::details::singleton<cds::urcu::general_instant_tag>::isUsed() ) {
220                         cds::urcu::details::singleton<cds::urcu::general_instant_tag>::detach_thread( m_pGPIRCU );
221                         m_pGPIRCU = nullptr;
222                     }
223                     if ( cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::isUsed() ) {
224                         cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::detach_thread( m_pGPBRCU );
225                         m_pGPBRCU = nullptr;
226                     }
227                     if ( cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::isUsed() ) {
228                         cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::detach_thread( m_pGPTRCU );
229                         m_pGPTRCU = nullptr;
230                     }
231 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
232                     if ( cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::isUsed() ) {
233                         cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::detach_thread( m_pSHBRCU );
234                         m_pSHBRCU = nullptr;
235                     }
236                     if ( cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::isUsed() ) {
237                         cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::detach_thread( m_pSHTRCU );
238                         m_pSHTRCU = nullptr;
239                     }
240 #endif
241                     return true;
242                 }
243                 return false;
244             }
245
246             size_t fake_current_processor()
247             {
248                 return m_nFakeProcessorNumber;
249             }
250             //@endcond
251         };
252         //@endcond
253
254     } // namespace threading
255 } // namespace cds::threading
256
257 #endif // #ifndef __CDS_THREADING__COMMON_H