2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
6 Source code repo: http://github.com/khizmax/libcds/
7 Download: http://sourceforge.net/projects/libcds/files/
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
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.
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.
31 #ifndef CDSLIB_THREADING__COMMON_H
32 #define CDSLIB_THREADING__COMMON_H
34 #include <cds/gc/impl/hp_decl.h>
35 #include <cds/gc/impl/dhp_decl.h>
37 #include <cds/urcu/details/gp_decl.h>
38 #include <cds/urcu/details/sh_decl.h>
39 #include <cds/algo/elimination_tls.h>
43 /** \anchor cds_threading
44 The \p CDS library requires support from the threads.
45 Each garbage collector manages a control structure on the per-thread basis.
46 The library does not dictate any thread model. To embed the library to your application you should choose
47 appropriate implementation of \p cds::threading::Manager interface
48 or should provide yourself.
49 The \p %cds::threading::Manager interface manages \p cds::threading::ThreadData structure that contains GC's thread specific data.
51 Any \p cds::threading::Manager implementation is a singleton and it must be accessible from any thread and from any point of
52 your application. Note that you should not mix different implementation of the \p cds::threading::Manager in your application.
54 Before compiling of your application you may define one of \p CDS_THREADING_xxx macro in cds/user_setup/threading.h file:
55 - \p CDS_THREADING_AUTODETECT - auto-detect appropriate threading model for your platform and compiler. This is
56 predefined value of threading model in <tt>cds/user_setup/threading.h</tt>.
57 - \p CDS_THREADING_WIN_TLS - use <tt>cds::threading::wintls::Manager</tt> implementation based on Windows TLS API.
58 Intended for Windows and Microsoft Visual C++ only. This is default threading model for Windows and MS Visual C++.
59 - \p CDS_THREADING_MSVC - use <tt>cds::threading::msvc::Manager</tt> implementation based on Microsoft Visual C++ <tt>__declspec(thread)</tt>
60 declaration. Intended for Windows and Microsoft Visual C++ only.
61 This macro should be explicitly specified if you want to use <tt>__declspec(thread)</tt> keyword.
62 - \p CDS_THREADING_PTHREAD - use <tt>cds::threading::pthread::Manager</tt> implementation based on pthread thread-specific
63 data functions \p pthread_getspecific / \p pthread_setspecific. Intended for GCC and clang compilers.
64 This is default threading model for GCC and clang.
65 - \p CDS_THREADING_GCC - use <tt>cds::threading::gcc::Manager</tt> implementation based on GCC \p __thread
66 keyword. Intended for GCC compiler only. Note, that GCC compiler supports \p __thread keyword properly
67 not for all platforms and even not for all GCC version.
68 This macro should be explicitly specified if you want to use \p __thread keyword.
69 - \p CDS_THREADING_CXX11 - use <tt>cds::threading::cxx11::Manager</tt> implementation based on \p thread_local
70 keyword introduced in C++11 standard. May be used only if your compiler supports C++11 thread-local storage.
71 - \p CDS_THREADING_USER_DEFINED - use user-provided threading model.
73 These macros select appropriate implementation of \p cds::threading::Manager class. The child namespaces of cds::threading
74 provide suitable implementation and import it to cds::threading by using \p using directive (or by using inline namespace if the compiler
75 supports it). So, if you need to call threading manager functions directly you should refer to \p cds::threading::Manager class.
77 @note Usually, you should not use \p cds::threading::Manager instance directly.
78 You may specify \p CDS_THREADING_xxx macro when building, everything else will setup automatically when you initialize the library,
79 see \ref cds_how_to_use "How to use libcds".
81 The interface of \p cds::threading::Manager class is the following:
85 // Initialize manager (called by cds::Initialize() )
88 // Terminate manager (called by cds::Terminate() )
91 // Checks whether current thread is attached to \p libcds feature or not.
92 static bool isThreadAttached();
94 // This method must be called in beginning of thread execution
95 // (called by ctor of GC thread object, for example, by ctor of cds::gc::HP::thread_gc)
96 static void attachThread();
98 // This method must be called in end of thread execution
99 // (called by dtor of GC thread object, for example, by dtor of cds::gc::HP::thread_gc)
100 static void detachThread();
102 // Get cds::gc::HP thread GC implementation for current thread
103 static gc::HP::thread_gc_impl& getHZPGC();
105 // Get cds::gc::DHP thread GC implementation for current thread;
106 static gc::DHP::thread_gc_impl& getDHPGC();
110 The library's core (dynamic linked library) is free of usage of user-supplied \p cds::threading::Manager code.
111 \p cds::threading::Manager is necessary for header-only part of \p CDS library (for \ref cds::threading::getGC functions).
114 Each thread that uses \p libcds data structures should be attached to threading::Manager before using
115 lock-free data structs.
116 See \ref cds_how_to_use "How to use" section for details
118 <b>Note for Windows</b>
120 When you use Garbage Collectors (GC) provided by \p libcds in your dll that dynamically loaded by \p LoadLibrary then there is no way
121 to use \p __declspec(thread) declaration to support threading model for \p libcds. MSDN says:
123 \li If a DLL declares any nonlocal data or object as __declspec( thread ), it can cause a protection fault if dynamically loaded.
124 After the DLL is loaded with \p LoadLibrary, it causes system failure whenever the code references the nonlocal __declspec( thread ) data.
125 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
126 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
127 this space to allow for the thread local variables declared with __declspec( thread ). Use the TLS APIs, such as TlsAlloc, in your
128 DLL to allocate TLS if the DLL might be loaded with LoadLibrary.
130 Thus, in case when \p libcds or a dll that depends on \p libcds is loaded dynamically by calling \p LoadLibrary explicitly,
131 you should not use \p CDS_THREADING_MSVC macro. Instead, you should build your dll projects with \p CDS_THREADING_WIN_TLS only.
133 namespace threading {
136 /// Thread-specific data
140 char CDS_DATA_ALIGNMENT(8) m_hpManagerPlaceholder[sizeof(cds::gc::HP::thread_gc_impl)]; ///< Michael's Hazard Pointer GC placeholder
141 char CDS_DATA_ALIGNMENT(8) m_dhpManagerPlaceholder[sizeof(cds::gc::DHP::thread_gc_impl)]; ///< Dynamic Hazard Pointer GC placeholder
143 cds::urcu::details::thread_data< cds::urcu::general_instant_tag > * m_pGPIRCU;
144 cds::urcu::details::thread_data< cds::urcu::general_buffered_tag > * m_pGPBRCU;
145 cds::urcu::details::thread_data< cds::urcu::general_threaded_tag > * m_pGPTRCU;
146 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
147 cds::urcu::details::thread_data< cds::urcu::signal_buffered_tag > * m_pSHBRCU;
148 cds::urcu::details::thread_data< cds::urcu::signal_threaded_tag > * m_pSHTRCU;
153 cds::gc::HP::thread_gc_impl * m_hpManager ; ///< Michael's Hazard Pointer GC thread-specific data
154 cds::gc::DHP::thread_gc_impl * m_dhpManager ; ///< Dynamic Hazard Pointer GC thread-specific data
156 size_t m_nFakeProcessorNumber ; ///< fake "current processor" number
159 size_t m_nAttachCount;
162 /// Per-thread elimination record
163 cds::algo::elimination::record m_EliminationRec;
166 static CDS_EXPORT_API atomics::atomic<size_t> s_nLastUsedProcNo;
167 static CDS_EXPORT_API size_t s_nProcCount;
172 : m_pGPIRCU( nullptr )
173 , m_pGPBRCU( nullptr )
174 , m_pGPTRCU( nullptr )
175 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
176 , m_pSHBRCU( nullptr )
177 , m_pSHTRCU( nullptr )
179 , m_nFakeProcessorNumber( s_nLastUsedProcNo.fetch_add(1, atomics::memory_order_relaxed) % s_nProcCount )
182 if (cds::gc::HP::isUsed() )
183 m_hpManager = new (m_hpManagerPlaceholder) cds::gc::HP::thread_gc_impl;
185 m_hpManager = nullptr;
187 if ( cds::gc::DHP::isUsed() )
188 m_dhpManager = new (m_dhpManagerPlaceholder) cds::gc::DHP::thread_gc_impl;
190 m_dhpManager = nullptr;
196 typedef cds::gc::HP::thread_gc_impl hp_thread_gc_impl;
197 m_hpManager->~hp_thread_gc_impl();
198 m_hpManager = nullptr;
201 if ( m_dhpManager ) {
202 typedef cds::gc::DHP::thread_gc_impl dhp_thread_gc_impl;
203 m_dhpManager->~dhp_thread_gc_impl();
204 m_dhpManager = nullptr;
207 assert( m_pGPIRCU == nullptr );
208 assert( m_pGPBRCU == nullptr );
209 assert( m_pGPTRCU == nullptr );
210 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
211 assert( m_pSHBRCU == nullptr );
212 assert( m_pSHTRCU == nullptr );
218 if ( m_nAttachCount++ == 0 ) {
219 if ( cds::gc::HP::isUsed() )
221 if ( cds::gc::DHP::isUsed() )
222 m_dhpManager->init();
224 if ( cds::urcu::details::singleton<cds::urcu::general_instant_tag>::isUsed() )
225 m_pGPIRCU = cds::urcu::details::singleton<cds::urcu::general_instant_tag>::attach_thread();
226 if ( cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::isUsed() )
227 m_pGPBRCU = cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::attach_thread();
228 if ( cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::isUsed() )
229 m_pGPTRCU = cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::attach_thread();
230 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
231 if ( cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::isUsed() )
232 m_pSHBRCU = cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::attach_thread();
233 if ( cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::isUsed() )
234 m_pSHTRCU = cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::attach_thread();
241 if ( --m_nAttachCount == 0 ) {
242 if ( cds::gc::DHP::isUsed() )
243 m_dhpManager->fini();
244 if ( cds::gc::HP::isUsed() )
247 if ( cds::urcu::details::singleton<cds::urcu::general_instant_tag>::isUsed() ) {
248 cds::urcu::details::singleton<cds::urcu::general_instant_tag>::detach_thread( m_pGPIRCU );
251 if ( cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::isUsed() ) {
252 cds::urcu::details::singleton<cds::urcu::general_buffered_tag>::detach_thread( m_pGPBRCU );
255 if ( cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::isUsed() ) {
256 cds::urcu::details::singleton<cds::urcu::general_threaded_tag>::detach_thread( m_pGPTRCU );
259 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
260 if ( cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::isUsed() ) {
261 cds::urcu::details::singleton<cds::urcu::signal_buffered_tag>::detach_thread( m_pSHBRCU );
264 if ( cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::isUsed() ) {
265 cds::urcu::details::singleton<cds::urcu::signal_threaded_tag>::detach_thread( m_pSHTRCU );
274 size_t fake_current_processor()
276 return m_nFakeProcessorNumber;
282 } // namespace threading
283 } // namespace cds::threading
285 #endif // #ifndef CDSLIB_THREADING__COMMON_H