replace null_ptr<>() with nullptr
[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/hp_decl.h>
7 #include <cds/gc/hrc_decl.h>
8 #include <cds/gc/ptb_decl.h>
9
10 #include <cds/urcu/details/gp_decl.h>
11 #include <cds/urcu/details/sh_decl.h>
12 #include <cds/algo/elimination_tls.h>
13
14 namespace cds {
15     /// Threading support
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.
23
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.
26
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.
45
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.
49
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".
53
54         The interface of \p cds::threading::Manager class is the following:
55         \code
56         class Manager {
57         public:
58             // Initialize manager (called by cds::Initialize() )
59             static void init();
60
61             // Terminate manager (called by cds::Terminate() )
62             static void fini();
63
64             // Checks whether current thread is attached to \p libcds feature or not.
65             static bool isThreadAttached();
66
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();
70
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();
74
75             // Get cds::gc::HP thread GC implementation for current thread
76             static gc::HP::thread_gc_impl&   getHZPGC();
77
78             // Get cds::gc::HRC thread GC implementation for current thread
79             static gc::HRC::thread_gc_impl&   getHRCGC();
80
81             // Get cds::gc::PTB thread GC implementation for current thread;
82             static gc::PTB::thread_gc_impl&   getPTBGC();
83         };
84         \endcode
85
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).
88
89
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
93
94         <b>Note for Windows</b>
95
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:
98
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.
105
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.
108     */
109     namespace threading {
110
111         //@cond
112         /// Thread-specific data
113         struct ThreadData {
114
115             //@cond
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
119
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;
126 #endif
127
128             //@endcond
129
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
133
134             size_t  m_nFakeProcessorNumber  ;   ///< fake "current processor" number
135
136             //@cond
137             size_t  m_nAttachCount;
138             //@endcond
139
140             /// Per-thread elimination record
141             cds::algo::elimination::record   m_EliminationRec;
142
143             //@cond
144             static CDS_EXPORT_API CDS_ATOMIC::atomic<size_t> s_nLastUsedProcNo;
145             static CDS_EXPORT_API size_t                     s_nProcCount;
146             //@endcond
147
148             //@cond
149             ThreadData()
150                 : m_pGPIRCU( NULL )
151                 , m_pGPBRCU( NULL )
152                 , m_pGPTRCU( NULL )
153 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
154                 , m_pSHBRCU( NULL )
155                 , m_pSHTRCU( NULL )
156 #endif
157                 , m_nFakeProcessorNumber( s_nLastUsedProcNo.fetch_add(1, CDS_ATOMIC::memory_order_relaxed) % s_nProcCount )
158                 , m_nAttachCount(0)
159             {
160                 if (cds::gc::HP::isUsed() )
161                     m_hpManager = new (m_hpManagerPlaceholder) cds::gc::HP::thread_gc_impl;
162                 else
163                     m_hpManager = nullptr;
164
165                 if ( cds::gc::HRC::isUsed() )
166                     m_hrcManager = new (m_hrcManagerPlaceholder) cds::gc::HRC::thread_gc_impl;
167                 else
168                     m_hrcManager = nullptr;
169
170                 if ( cds::gc::PTB::isUsed() )
171                     m_ptbManager = new (m_ptbManagerPlaceholder) cds::gc::PTB::thread_gc_impl;
172                 else
173                     m_ptbManager = nullptr;
174             }
175
176             ~ThreadData()
177             {
178                 if ( m_hpManager ) {
179                     typedef cds::gc::HP::thread_gc_impl hp_thread_gc_impl;
180                     m_hpManager->~hp_thread_gc_impl();
181                     m_hpManager = nullptr;
182                 }
183
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;
188                 }
189
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;
194                 }
195
196                 assert( m_pGPIRCU == NULL );
197                 assert( m_pGPBRCU == NULL );
198                 assert( m_pGPTRCU == NULL );
199 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
200                 assert( m_pSHBRCU == NULL );
201                 assert( m_pSHTRCU == NULL );
202 #endif
203             }
204
205             void init()
206             {
207                 if ( m_nAttachCount++ == 0 ) {
208                     if ( cds::gc::HP::isUsed() )
209                         m_hpManager->init();
210                     if ( cds::gc::HRC::isUsed() )
211                         m_hrcManager->init();
212                     if ( cds::gc::PTB::isUsed() )
213                         m_ptbManager->init();
214
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();
226 #endif
227                 }
228             }
229
230             bool fini()
231             {
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() )
238                         m_hpManager->fini();
239
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 );
242                         m_pGPIRCU = NULL;
243                     }
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 );
246                         m_pGPBRCU = NULL;
247                     }
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 );
250                         m_pGPTRCU = NULL;
251                     }
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 );
255                         m_pSHBRCU = NULL;
256                     }
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 );
259                         m_pSHTRCU = NULL;
260                     }
261 #endif
262                     return true;
263                 }
264                 return false;
265             }
266
267             size_t fake_current_processor()
268             {
269                 return m_nFakeProcessorNumber;
270             }
271             //@endcond
272         };
273         //@endcond
274
275     } // namespace threading
276 } // namespace cds::threading
277
278 #endif // #ifndef __CDS_THREADING__COMMON_H