3 #ifndef __CDS_THREADING_DETAILS_WINTLS_MANAGER_H
4 #define __CDS_THREADING_DETAILS_WINTLS_MANAGER_H
7 #include <cds/threading/details/_common.h>
10 namespace cds { namespace threading {
12 /// cds::threading::Manager implementation based on Windows TLS API
13 CDS_CXX11_INLINE_NAMESPACE namespace wintls {
15 /// Thread-specific data manager based on Windows TLS API
17 Manager throws an exception of Manager::api_exception class if an error occurs
21 /// Windows TLS API error code type
22 typedef DWORD api_error_code;
25 class api_exception: public cds::Exception {
27 const api_error_code m_errCode ; ///< error code
29 /// Exception constructor
30 api_exception( api_error_code nCode, const char * pszFunction )
34 # if CDS_OS_TYPE == CDS_OS_MINGW
35 sprintf( buf, "Win32 TLS API error %lu [function %s]", nCode, pszFunction );
37 sprintf_s( buf, sizeof(buf)/sizeof(buf[0]), "Win32 TLS API error %lu [function %s]", nCode, pszFunction );
55 static CDS_EXPORT_API DWORD m_key;
59 if ( m_key == TLS_OUT_OF_INDEXES ) {
60 if ( (m_key = ::TlsAlloc()) == TLS_OUT_OF_INDEXES )
61 throw api_exception( ::GetLastError(), "TlsAlloc" );
67 if ( m_key != TLS_OUT_OF_INDEXES ) {
68 if ( ::TlsFree( m_key ) == 0 )
69 throw api_exception( ::GetLastError(), "TlsFree" );
70 m_key = TLS_OUT_OF_INDEXES;
74 static ThreadData * get()
77 void * pData = ::TlsGetValue( m_key );
78 if ( pData == nullptr && (nErr = ::GetLastError()) != ERROR_SUCCESS )
79 throw api_exception( nErr, "TlsGetValue" );
80 return reinterpret_cast<ThreadData *>( pData );
85 ThreadData * pData = new ThreadData;
86 if ( !::TlsSetValue( m_key, pData ))
87 throw api_exception( ::GetLastError(), "TlsSetValue" );
91 ThreadData * p = get();
92 ::TlsSetValue( m_key, nullptr );
100 static ThreadData * _threadData( EThreadAction nAction )
106 ThreadData * p = Holder::get();
111 return Holder::get();
114 return Holder::get();
115 case do_attachThread:
116 if ( Holder::get() == nullptr )
118 return Holder::get();
119 case do_detachThread:
123 assert( false ) ; // anything forgotten?..
130 /// Initialize manager
132 This function is automatically called by cds::Initialize
139 /// Terminate manager
141 This function is automatically called by cds::Terminate
148 /// Checks whether current thread is attached to \p libcds feature or not.
149 static bool isThreadAttached()
151 return _threadData( do_checkData ) != nullptr;
154 /// This method must be called in beginning of thread execution
156 If TLS pointer to manager's data is \p nullptr, api_exception is thrown
158 If an error occurs in call of Win TLS API function, api_exception is thrown
159 with Windows error code.
161 static void attachThread()
163 ThreadData * pData = _threadData( do_attachThread );
170 throw api_exception( api_error_code(-1), "cds::threading::wintls::Manager::attachThread" );
173 /// This method must be called in end of thread execution
175 If TLS pointer to manager's data is \p nullptr, api_exception is thrown
177 If an error occurs in call of Win TLS API function, api_exception is thrown
178 with Windows error code.
180 static void detachThread()
182 ThreadData * pData = _threadData( do_getData );
187 _threadData( do_detachThread );
190 throw api_exception( api_error_code(-1), "cds::threading::winapi::Manager::detachThread" );
193 /// Returns ThreadData pointer for the current thread
194 static ThreadData * thread_data()
196 return _threadData( do_getData );
199 /// Get gc::HP thread GC implementation for current thread
201 The object returned may be uninitialized if you did not call attachThread in the beginning of thread execution
202 or if you did not use gc::HP.
203 To initialize gc::HP GC you must constuct cds::gc::HP object in the beginning of your application
205 static gc::HP::thread_gc_impl& getHZPGC()
207 return *(_threadData( do_getData )->m_hpManager);
210 /// Get gc::PTB thread GC implementation for current thread
212 The object returned may be uninitialized if you did not call attachThread in the beginning of thread execution
213 or if you did not use gc::PTB.
214 To initialize gc::PTB GC you must constuct cds::gc::PTB object in the beginning of your application
216 static gc::PTB::thread_gc_impl& getPTBGC()
218 return *(_threadData( do_getData )->m_ptbManager);
222 static size_t fake_current_processor()
224 return _threadData( do_getData )->fake_current_processor();
229 } // namespace wintls
230 }} // namespace cds::threading
233 #endif // #ifndef __CDS_THREADING_DETAILS_WINTLS_MANAGER_H