Updated copyright
[libcds.git] / cds / threading / details / _common.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-2017
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_THREADING__COMMON_H
32 #define CDSLIB_THREADING__COMMON_H
33
34 #include <cds/gc/impl/hp_decl.h>
35 #include <cds/gc/impl/dhp_decl.h>
36
37 #include <cds/urcu/details/gp_decl.h>
38 #include <cds/urcu/details/sh_decl.h>
39 #include <cds/algo/elimination_tls.h>
40
41 namespace cds {
42     /// Threading support
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.
50
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.
53
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.
72
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.
76
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".
80
81         The interface of \p cds::threading::Manager class is the following:
82         \code
83         class Manager {
84         public:
85             // Initialize manager (called by cds::Initialize())
86             static void init();
87
88             // Terminate manager (called by cds::Terminate())
89             static void fini();
90
91             // Checks whether current thread is attached to \p libcds feature or not.
92             static bool isThreadAttached();
93
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();
97
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();
101
102             // Get cds::gc::HP thread GC implementation for current thread
103             static gc::HP::thread_gc_impl&   getHZPGC();
104
105             // Get cds::gc::DHP thread GC implementation for current thread;
106             static gc::DHP::thread_gc_impl&   getDHPGC();
107         };
108         \endcode
109
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).
112
113
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
117
118         <b>Note for Windows</b>
119
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:
122
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.
129
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.
132     */
133     namespace threading {
134
135         //@cond
136         /// Thread-specific data
137         struct ThreadData {
138
139             //@cond
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
142
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;
149 #endif
150
151             //@endcond
152
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
155
156             size_t  m_nFakeProcessorNumber  ;   ///< fake "current processor" number
157
158             //@cond
159             size_t  m_nAttachCount;
160             //@endcond
161
162             /// Per-thread elimination record
163             cds::algo::elimination::record   m_EliminationRec;
164
165             //@cond
166             static CDS_EXPORT_API atomics::atomic<size_t> s_nLastUsedProcNo;
167             static CDS_EXPORT_API size_t                     s_nProcCount;
168             //@endcond
169
170             //@cond
171             ThreadData()
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 )
178 #endif
179                 , m_nFakeProcessorNumber( s_nLastUsedProcNo.fetch_add(1, atomics::memory_order_relaxed) % s_nProcCount )
180                 , m_nAttachCount(0)
181             {
182                 if (cds::gc::HP::isUsed())
183                     m_hpManager = new (m_hpManagerPlaceholder) cds::gc::HP::thread_gc_impl;
184                 else
185                     m_hpManager = nullptr;
186
187                 if ( cds::gc::DHP::isUsed())
188                     m_dhpManager = new (m_dhpManagerPlaceholder) cds::gc::DHP::thread_gc_impl;
189                 else
190                     m_dhpManager = nullptr;
191             }
192
193             ~ThreadData()
194             {
195                 if ( m_hpManager ) {
196                     typedef cds::gc::HP::thread_gc_impl hp_thread_gc_impl;
197                     m_hpManager->~hp_thread_gc_impl();
198                     m_hpManager = nullptr;
199                 }
200
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;
205                 }
206
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 );
213 #endif
214             }
215
216             void init()
217             {
218                 if ( m_nAttachCount++ == 0 ) {
219                     if ( cds::gc::HP::isUsed())
220                         m_hpManager->init();
221                     if ( cds::gc::DHP::isUsed())
222                         m_dhpManager->init();
223
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();
235 #endif
236                 }
237             }
238
239             bool fini()
240             {
241                 if ( --m_nAttachCount == 0 ) {
242                     if ( cds::gc::DHP::isUsed())
243                         m_dhpManager->fini();
244                     if ( cds::gc::HP::isUsed())
245                         m_hpManager->fini();
246
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 );
249                         m_pGPIRCU = nullptr;
250                     }
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 );
253                         m_pGPBRCU = nullptr;
254                     }
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 );
257                         m_pGPTRCU = nullptr;
258                     }
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 );
262                         m_pSHBRCU = nullptr;
263                     }
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 );
266                         m_pSHTRCU = nullptr;
267                     }
268 #endif
269                     return true;
270                 }
271                 return false;
272             }
273
274             size_t fake_current_processor()
275             {
276                 return m_nFakeProcessorNumber;
277             }
278             //@endcond
279         };
280         //@endcond
281
282     } // namespace threading
283 } // namespace cds::threading
284
285 #endif // #ifndef CDSLIB_THREADING__COMMON_H