3 #ifndef __CDS_THREADING__COMMON_H
4 #define __CDS_THREADING__COMMON_H
6 #include <cds/gc/hp_decl.h>
7 #include <cds/gc/hrc_decl.h>
8 #include <cds/gc/ptb_decl.h>
10 #include <cds/urcu/details/gp_decl.h>
11 #include <cds/urcu/details/sh_decl.h>
12 #include <cds/algo/elimination_tls.h>
16 /** \anchor cds_threading
17 The \p CDS library requires support from the threads.
18 Each garbage collector manages a control structure on the per-thread basis.
19 The library does not dictate any thread model. To embed the library to your application you should choose
20 appropriate implementation of \p cds::threading::Manager interface
21 or should provide yourself.
22 The \p %cds::threading::Manager interface manages \p ñds::threading::ThreadData structure that contains GC's thread specific data.
24 Any \p cds::threading::Manager implementation is a singleton and it must be accessible from any thread and from any point of
25 your application. Note that you should not mix different implementation of the \p cds::threading::Manager in your application.
27 Before compiling of your application you may define one of \p CDS_THREADING_xxx macro in cds/user_setup/threading.h file:
28 - \p CDS_THREADING_AUTODETECT - auto-detect appropriate threading model for your platform and compiler. This is
29 predefined value of threading model in <tt>cds/user_setup/threading.h</tt>.
30 - \p CDS_THREADING_WIN_TLS - use <tt>cds::threading::wintls::Manager</tt> implementation based on Windows TLS API.
31 Intended for Windows and Microsoft Visual C++ only. This is default threading model for Windows and MS Visual C++.
32 - \p CDS_THREADING_MSVC - use <tt>cds::threading::msvc::Manager</tt> implementation based on Microsoft Visual C++ <tt>__declspec(thread)</tt>
33 declaration. Intended for Windows and Microsoft Visual C++ only.
34 This macro should be explicitly specified if you want to use <tt>__declspec(thread)</tt> keyword.
35 - \p CDS_THREADING_PTHREAD - use <tt>cds::threading::pthread::Manager</tt> implementation based on pthread thread-specific
36 data functions \p pthread_getspecific / \p pthread_setspecific. Intended for GCC and clang compilers.
37 This is default threading model for GCC and clang.
38 - \p CDS_THREADING_GCC - use <tt>cds::threading::gcc::Manager</tt> implementation based on GCC \p __thread
39 keyword. Intended for GCC compiler only. Note, that GCC compiler supports \p __thread keyword properly
40 not for all platforms and even not for all GCC version.
41 This macro should be explicitly specified if you want to use \p __thread keyword.
42 - \p CDS_THREADING_CXX11 - use <tt>cds::threading::cxx11::Manager</tt> implementation based on \p thread_local
43 keyword introduced in C++11 standard. May be used only if your compiler supports C++11 thread-local storage.
44 - \p CDS_THREADING_USER_DEFINED - use user-provided threading model.
46 These macros select appropriate implementation of \p cds::threading::Manager class. The child namespaces of cds::threading
47 provide suitable implementation and import it to cds::threading by using \p using directive (or by using inline namespace if the compiler
48 supports it). So, if you need to call threading manager functions directly you should refer to \p cds::threading::Manager class.
50 @note Usually, you should not use \p cds::threading::Manager instance directly.
51 You may specify \p CDS_THREADING_xxx macro when building, everything else will setup automatically when you initialize the library,
52 see \ref cds_how_to_use "How to use libcds".
54 The interface of \p cds::threading::Manager class is the following:
58 // Initialize manager (called by cds::Initialize() )
61 // Terminate manager (called by cds::Terminate() )
64 // Checks whether current thread is attached to \p libcds feature or not.
65 static bool isThreadAttached();
67 // This method must be called in beginning of thread execution
68 // (called by ctor of GC thread object, for example, by ctor of cds::gc::HP::thread_gc)
69 static void attachThread();
71 // This method must be called in end of thread execution
72 // (called by dtor of GC thread object, for example, by dtor of cds::gc::HP::thread_gc)
73 static void detachThread();
75 // Get cds::gc::HP thread GC implementation for current thread
76 static gc::HP::thread_gc_impl& getHZPGC();
78 // Get cds::gc::HRC thread GC implementation for current thread
79 static gc::HRC::thread_gc_impl& getHRCGC();
81 // Get cds::gc::PTB thread GC implementation for current thread;
82 static gc::PTB::thread_gc_impl& getPTBGC();
86 The library's core (dynamic linked library) is free of usage of user-supplied \p cds::threading::Manager code.
87 \p cds::threading::Manager is necessary for header-only part of \p CDS library (for \ref cds::threading::getGC functions).
90 Each thread that uses \p libcds data structures should be attached to threading::Manager before using
91 lock-free data structs.
92 See \ref cds_how_to_use "How to use" section for details
94 <b>Note for Windows</b>
96 When you use Garbage Collectors (GC) provided by \p libcds in your dll that dynamically loaded by \p LoadLibrary then there is no way
97 to use \p __declspec(thread) declaration to support threading model for \p libcds. MSDN says:
99 \li If a DLL declares any nonlocal data or object as __declspec( thread ), it can cause a protection fault if dynamically loaded.
100 After the DLL is loaded with \p LoadLibrary, it causes system failure whenever the code references the nonlocal __declspec( thread ) data.
101 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
102 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
103 this space to allow for the thread local variables declared with __declspec( thread ). Use the TLS APIs, such as TlsAlloc, in your
104 DLL to allocate TLS if the DLL might be loaded with LoadLibrary.
106 Thus, in case when \p libcds or a dll that depends on \p libcds is loaded dynamically by calling \p LoadLibrary explicitly,
107 you should not use \p CDS_THREADING_MSVC macro. Instead, you should build your dll projects with \p CDS_THREADING_WIN_TLS only.
109 namespace threading {
112 /// Thread-specific data
116 char CDS_DATA_ALIGNMENT(8) m_hpManagerPlaceholder[sizeof(cds::gc::HP::thread_gc_impl)] ; ///< Michael's Hazard Pointer GC placeholder
117 char CDS_DATA_ALIGNMENT(8) m_hrcManagerPlaceholder[sizeof(cds::gc::HRC::thread_gc_impl)] ; ///< Gidenstam's GC placeholder
118 char CDS_DATA_ALIGNMENT(8) m_ptbManagerPlaceholder[sizeof(cds::gc::PTB::thread_gc_impl)] ; ///< Pass The Buck GC placeholder
120 cds::urcu::details::thread_data< cds::urcu::general_instant_tag > * m_pGPIRCU;
121 cds::urcu::details::thread_data< cds::urcu::general_buffered_tag > * m_pGPBRCU;
122 cds::urcu::details::thread_data< cds::urcu::general_threaded_tag > * m_pGPTRCU;
123 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
124 cds::urcu::details::thread_data< cds::urcu::signal_buffered_tag > * m_pSHBRCU;
125 cds::urcu::details::thread_data< cds::urcu::signal_threaded_tag > * m_pSHTRCU;
130 cds::gc::HP::thread_gc_impl * m_hpManager ; ///< Michael's Hazard Pointer GC thread-specific data
131 cds::gc::HRC::thread_gc_impl * m_hrcManager ; ///< Gidenstam's GC thread-specific data
132 cds::gc::PTB::thread_gc_impl * m_ptbManager ; ///< Pass The Buck GC thread-specific data
134 size_t m_nFakeProcessorNumber ; ///< fake "current processor" number
137 size_t m_nAttachCount;
140 /// Per-thread elimination record
141 cds::algo::elimination::record m_EliminationRec;
144 static CDS_EXPORT_API atomics::atomic<size_t> s_nLastUsedProcNo;
145 static CDS_EXPORT_API size_t s_nProcCount;
150 : m_pGPIRCU( nullptr )
151 , m_pGPBRCU( nullptr )
152 , m_pGPTRCU( nullptr )
153 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
154 , m_pSHBRCU( nullptr )
155 , m_pSHTRCU( nullptr )
157 , m_nFakeProcessorNumber( s_nLastUsedProcNo.fetch_add(1, atomics::memory_order_relaxed) % s_nProcCount )
160 if (cds::gc::HP::isUsed() )
161 m_hpManager = new (m_hpManagerPlaceholder) cds::gc::HP::thread_gc_impl;
163 m_hpManager = nullptr;
165 if ( cds::gc::HRC::isUsed() )
166 m_hrcManager = new (m_hrcManagerPlaceholder) cds::gc::HRC::thread_gc_impl;
168 m_hrcManager = nullptr;
170 if ( cds::gc::PTB::isUsed() )
171 m_ptbManager = new (m_ptbManagerPlaceholder) cds::gc::PTB::thread_gc_impl;
173 m_ptbManager = nullptr;
179 typedef cds::gc::HP::thread_gc_impl hp_thread_gc_impl;
180 m_hpManager->~hp_thread_gc_impl();
181 m_hpManager = nullptr;
184 if ( m_hrcManager ) {
185 typedef cds::gc::HRC::thread_gc_impl hrc_thread_gc_impl;
186 m_hrcManager->~hrc_thread_gc_impl();
187 m_hrcManager = nullptr;
190 if ( m_ptbManager ) {
191 typedef cds::gc::PTB::thread_gc_impl ptb_thread_gc_impl;
192 m_ptbManager->~ptb_thread_gc_impl();
193 m_ptbManager = nullptr;
196 assert( m_pGPIRCU == nullptr );
197 assert( m_pGPBRCU == nullptr );
198 assert( m_pGPTRCU == nullptr );
199 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
200 assert( m_pSHBRCU == nullptr );
201 assert( m_pSHTRCU == nullptr );
207 if ( m_nAttachCount++ == 0 ) {
208 if ( cds::gc::HP::isUsed() )
210 if ( cds::gc::HRC::isUsed() )
211 m_hrcManager->init();
212 if ( cds::gc::PTB::isUsed() )
213 m_ptbManager->init();
215 if ( cds::urcu::details::singleton<cds::urcu::general_instant_tag>::isUsed() )
216 m_pGPIRCU = cds::urcu::details::singleton<cds::urcu::general_instant_tag>::attach_thread();
217 if ( cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::isUsed() )
218 m_pGPBRCU = cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::attach_thread();
219 if ( cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::isUsed() )
220 m_pGPTRCU = cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::attach_thread();
221 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
222 if ( cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::isUsed() )
223 m_pSHBRCU = cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::attach_thread();
224 if ( cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::isUsed() )
225 m_pSHTRCU = cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::attach_thread();
232 if ( --m_nAttachCount == 0 ) {
233 if ( cds::gc::PTB::isUsed() )
234 m_ptbManager->fini();
235 if ( cds::gc::HRC::isUsed() )
236 m_hrcManager->fini();
237 if ( cds::gc::HP::isUsed() )
240 if ( cds::urcu::details::singleton<cds::urcu::general_instant_tag>::isUsed() ) {
241 cds::urcu::details::singleton<cds::urcu::general_instant_tag>::detach_thread( m_pGPIRCU );
244 if ( cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::isUsed() ) {
245 cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::detach_thread( m_pGPBRCU );
248 if ( cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::isUsed() ) {
249 cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::detach_thread( m_pGPTRCU );
252 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
253 if ( cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::isUsed() ) {
254 cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::detach_thread( m_pSHBRCU );
257 if ( cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::isUsed() ) {
258 cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::detach_thread( m_pSHTRCU );
267 size_t fake_current_processor()
269 return m_nFakeProcessorNumber;
275 } // namespace threading
276 } // namespace cds::threading
278 #endif // #ifndef __CDS_THREADING__COMMON_H