3 #ifndef __CDS_THREADING_DETAILS_WINTLS_MANAGER_H
4 #define __CDS_THREADING_DETAILS_WINTLS_MANAGER_H
6 #include <system_error>
8 #include <cds/threading/details/_common.h>
11 namespace cds { namespace threading {
13 /// cds::threading::Manager implementation based on Windows TLS API
14 CDS_CXX11_INLINE_NAMESPACE namespace wintls {
16 /// Thread-specific data manager based on Windows TLS API
18 Manager throws an exception of Manager::api_exception class if an error occurs
22 /// Windows TLS API error code type
23 typedef DWORD api_error_code;
26 class api_exception : public std::system_error
29 /// Exception constructor
30 api_exception( api_error_code nCode, const char * pszFunction )
31 : std::system_error( static_cast<int>(nCode), std::system_category(), pszFunction )
47 static CDS_EXPORT_API DWORD m_key;
51 if ( m_key == TLS_OUT_OF_INDEXES ) {
52 if ( (m_key = ::TlsAlloc()) == TLS_OUT_OF_INDEXES )
53 throw api_exception( ::GetLastError(), "TlsAlloc" );
59 if ( m_key != TLS_OUT_OF_INDEXES ) {
60 if ( ::TlsFree( m_key ) == 0 )
61 throw api_exception( ::GetLastError(), "TlsFree" );
62 m_key = TLS_OUT_OF_INDEXES;
66 static ThreadData * get()
69 void * pData = ::TlsGetValue( m_key );
70 if ( pData == nullptr && (nErr = ::GetLastError()) != ERROR_SUCCESS )
71 throw api_exception( nErr, "TlsGetValue" );
72 return reinterpret_cast<ThreadData *>( pData );
77 ThreadData * pData = new ThreadData;
78 if ( !::TlsSetValue( m_key, pData ))
79 throw api_exception( ::GetLastError(), "TlsSetValue" );
83 ThreadData * p = get();
84 ::TlsSetValue( m_key, nullptr );
92 static ThreadData * _threadData( EThreadAction nAction )
98 ThreadData * p = Holder::get();
103 return Holder::get();
106 return Holder::get();
107 case do_attachThread:
108 if ( Holder::get() == nullptr )
110 return Holder::get();
111 case do_detachThread:
115 assert( false ) ; // anything forgotten?..
122 /// Initialize manager
124 This function is automatically called by cds::Initialize
131 /// Terminate manager
133 This function is automatically called by cds::Terminate
140 /// Checks whether current thread is attached to \p libcds feature or not.
141 static bool isThreadAttached()
143 return _threadData( do_checkData ) != nullptr;
146 /// This method must be called in beginning of thread execution
148 If TLS pointer to manager's data is \p nullptr, api_exception is thrown
150 If an error occurs in call of Win TLS API function, api_exception is thrown
151 with Windows error code.
153 static void attachThread()
155 ThreadData * pData = _threadData( do_attachThread );
162 throw api_exception( api_error_code(-1), "cds::threading::wintls::Manager::attachThread" );
165 /// This method must be called in end of thread execution
167 If TLS pointer to manager's data is \p nullptr, api_exception is thrown
169 If an error occurs in call of Win TLS API function, api_exception is thrown
170 with Windows error code.
172 static void detachThread()
174 ThreadData * pData = _threadData( do_getData );
179 _threadData( do_detachThread );
182 throw api_exception( api_error_code(-1), "cds::threading::winapi::Manager::detachThread" );
185 /// Returns ThreadData pointer for the current thread
186 static ThreadData * thread_data()
188 return _threadData( do_getData );
191 /// Get gc::HP thread GC implementation for current thread
193 The object returned may be uninitialized if you did not call attachThread in the beginning of thread execution
194 or if you did not use gc::HP.
195 To initialize gc::HP GC you must constuct cds::gc::HP object in the beginning of your application
197 static gc::HP::thread_gc_impl& getHZPGC()
199 return *(_threadData( do_getData )->m_hpManager);
202 /// Get gc::DHP thread GC implementation for current thread
204 The object returned may be uninitialized if you did not call attachThread in the beginning of thread execution
205 or if you did not use gc::DHP.
206 To initialize gc::DHP GC you must constuct cds::gc::DHP object in the beginning of your application
208 static gc::DHP::thread_gc_impl& getDHPGC()
210 return *(_threadData( do_getData )->m_dhpManager);
214 static size_t fake_current_processor()
216 return _threadData( do_getData )->fake_current_processor();
221 } // namespace wintls
222 }} // namespace cds::threading
225 #endif // #ifndef __CDS_THREADING_DETAILS_WINTLS_MANAGER_H