1 // $Id$ 2 // (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004. 3 // (C) Copyright 2007 Roland Schwarz 4 // (C) Copyright 2007 Anthony Williams 5 // (C) Copyright 2007 David Deakins 6 // Use, modification and distribution are subject to the 7 // Boost Software License, Version 1.0. (See accompanying file 8 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 10 #include <boost/winapi/config.hpp> 11 #include <boost/thread/detail/config.hpp> 12 13 #if defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_LIB) 14 15 #if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) 16 17 #include <boost/thread/detail/tss_hooks.hpp> 18 19 #include <windows.h> 20 21 #include <cstdlib> 22 23 namespace boost 24 { tss_cleanup_implemented()25 void tss_cleanup_implemented() {} 26 } 27 28 namespace { on_tls_callback(void *,DWORD dwReason,PVOID)29 void NTAPI on_tls_callback(void* , DWORD dwReason, PVOID ) 30 { 31 switch (dwReason) 32 { 33 case DLL_THREAD_DETACH: 34 { 35 boost::on_thread_exit(); 36 break; 37 } 38 } 39 } 40 } 41 42 #if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || (__MINGW32__) || (__MINGW32_MAJOR_VERSION >3) || \ 43 ((__MINGW32_MAJOR_VERSION==3) && (__MINGW32_MINOR_VERSION>=18)) 44 extern "C" 45 { 46 PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback; 47 } 48 #else 49 extern "C" { 50 51 void (* after_ctors )() __attribute__((section(".ctors"))) = boost::on_process_enter; 52 void (* before_dtors)() __attribute__((section(".dtors"))) = boost::on_thread_exit; 53 void (* after_dtors )() __attribute__((section(".dtors.zzz"))) = boost::on_process_exit; 54 55 ULONG __tls_index__ = 0; 56 char __tls_end__ __attribute__((section(".tls$zzz"))) = 0; 57 char __tls_start__ __attribute__((section(".tls"))) = 0; 58 59 60 PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0; 61 PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0; 62 } 63 extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) = 64 { 65 (DWORD) &__tls_start__, 66 (DWORD) &__tls_end__, 67 (DWORD) &__tls_index__, 68 (DWORD) (&__crt_xl_start__+1), 69 (DWORD) 0, 70 (DWORD) 0 71 }; 72 #endif 73 74 75 #elif defined(_MSC_VER) && !defined(UNDER_CE) 76 77 #include <boost/thread/detail/tss_hooks.hpp> 78 79 #include <stdlib.h> 80 81 #include <windows.h> 82 83 84 // _pRawDllMainOrig can be defined by including boost/thread/win32/mfc_thread_init.hpp 85 // into your dll; it ensures that MFC-Dll-initialization will be done properly 86 // The following code is adapted from the MFC-Dll-init code 87 /* 88 * _pRawDllMainOrig MUST be an extern const variable, which will be aliased to 89 * _pDefaultRawDllMainOrig if no real user definition is present, thanks to the 90 * alternatename directive. 91 */ 92 93 // work at least with _MSC_VER 1500 (MSVC++ 9.0, VS 2008) 94 #if (_MSC_VER >= 1500) 95 96 extern "C" { 97 extern BOOL (WINAPI * const _pRawDllMainOrig)(HINSTANCE, DWORD, LPVOID); 98 extern BOOL (WINAPI * const _pDefaultRawDllMainOrig)(HINSTANCE, DWORD, LPVOID) = NULL; 99 #if defined (_M_IX86) 100 #pragma comment(linker, "/alternatename:__pRawDllMainOrig=__pDefaultRawDllMainOrig") 101 #elif defined (_M_X64) || defined (_M_ARM) || defined (_M_ARM64) 102 #pragma comment(linker, "/alternatename:_pRawDllMainOrig=_pDefaultRawDllMainOrig") 103 #else /* unknown Windows target (not x86, x64, ARM, ARM64) */ 104 #error Unsupported platform 105 #endif /* defined (_M_X64) || defined (_M_ARM) || defined (_M_ARM64) */ 106 } 107 108 #endif 109 110 111 112 113 //Definitions required by implementation 114 #if (_MSC_VER < 1300) || ((_MSC_VER > 1900) && (_MSC_VER < 1910)) // 1300 == VC++ 7.0, 1900 == VC++ 14.0, 1910 == VC++ 2017 115 typedef void ( __cdecl *_PVFV_ )(); 116 typedef void ( __cdecl *_PIFV_ )(); 117 #define INIRETSUCCESS_V 118 #define INIRETSUCCESS_I 119 #define PVAPI_V void __cdecl 120 #define PVAPI_I void __cdecl 121 #elif (_MSC_VER >= 1910) 122 typedef void ( __cdecl *_PVFV_ )(); 123 typedef int ( __cdecl *_PIFV_ )(); 124 #define INIRETSUCCESS_V 125 #define INIRETSUCCESS_I 0 126 #define PVAPI_V void __cdecl 127 #define PVAPI_I int __cdecl 128 #else 129 typedef int ( __cdecl *_PVFV_ )(); 130 typedef int ( __cdecl *_PIFV_ )(); 131 #define INIRETSUCCESS_V 0 132 #define INIRETSUCCESS_I 0 133 #define PVAPI_V int __cdecl 134 #define PVAPI_I int __cdecl 135 #endif 136 137 typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID); 138 139 //Symbols for connection to the runtime environment 140 141 extern "C" 142 { 143 extern DWORD _tls_used; //the tls directory (located in .rdata segment) 144 extern _TLSCB __xl_a[], __xl_z[]; //tls initializers */ 145 } 146 147 namespace 148 { 149 //Forward declarations 150 151 static PVAPI_I on_tls_prepare(); 152 static PVAPI_V on_process_init(); 153 static PVAPI_V on_process_term(); 154 static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID); 155 } 156 157 namespace boost 158 { 159 //The .CRT$Xxx information is taken from Codeguru: 160 //http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/ 161 162 // Variables below are not referenced anywhere and 163 // to not be optimized away has to have external linkage 164 165 #if (_MSC_VER >= 1400) 166 #pragma section(".CRT$XIU",long,read) 167 #pragma section(".CRT$XCU",long,read) 168 #pragma section(".CRT$XTU",long,read) 169 #pragma section(".CRT$XLC",long,read) 170 extern const __declspec(allocate(".CRT$XLC")) _TLSCB p_tls_callback = on_tls_callback; 171 extern const __declspec(allocate(".CRT$XIU")) _PIFV_ p_tls_prepare = on_tls_prepare; 172 extern const __declspec(allocate(".CRT$XCU")) _PVFV_ p_process_init = on_process_init; 173 extern const __declspec(allocate(".CRT$XTU")) _PVFV_ p_process_term = on_process_term; 174 #else 175 #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 176 # pragma data_seg(push, old_seg) 177 #endif 178 //Callback to run tls glue code first. 179 //I don't think it is necessary to run it 180 //at .CRT$XIB level, since we are only 181 //interested in thread detachement. But 182 //this could be changed easily if required. 183 184 #pragma data_seg(".CRT$XIU") 185 extern const _PIFV_ p_tls_prepare = on_tls_prepare; 186 #pragma data_seg() 187 188 //Callback after all global ctors. 189 190 #pragma data_seg(".CRT$XCU") 191 extern const _PVFV_ p_process_init = on_process_init; 192 #pragma data_seg() 193 194 //Callback for tls notifications. 195 196 #pragma data_seg(".CRT$XLB") 197 extern const _TLSCB p_thread_callback = on_tls_callback; 198 #pragma data_seg() 199 //Callback for termination. 200 201 #pragma data_seg(".CRT$XTU") 202 extern const _PVFV_ p_process_term = on_process_term; 203 #pragma data_seg() 204 #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 205 # pragma data_seg(pop, old_seg) 206 #endif 207 #endif 208 } // namespace boost 209 210 namespace 211 { 212 #ifdef BOOST_MSVC 213 #pragma warning(push) 214 #pragma warning(disable:4189) 215 #endif 216 on_tls_prepare()217 PVAPI_I on_tls_prepare() 218 { 219 //The following line has an important side effect: 220 //if the TLS directory is not already there, it will 221 //be created by the linker. In other words, it forces a tls 222 //directory to be generated by the linker even when static tls 223 //(i.e. __declspec(thread)) is not used. 224 //The volatile should prevent the optimizer 225 //from removing the reference. 226 227 DWORD volatile dw = _tls_used; 228 229 #if (_MSC_VER < 1300) // 1300 == VC++ 7.0 230 _TLSCB* pfbegin = __xl_a; 231 _TLSCB* pfend = __xl_z; 232 _TLSCB* pfdst = pfbegin; 233 //pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks; 234 235 //The following loop will merge the address pointers 236 //into a contiguous area, since the tlssup code seems 237 //to require this (at least on MSVC 6) 238 239 while (pfbegin < pfend) 240 { 241 if (*pfbegin != 0) 242 { 243 *pfdst = *pfbegin; 244 ++pfdst; 245 } 246 ++pfbegin; 247 } 248 249 *pfdst = 0; 250 #endif 251 252 return INIRETSUCCESS_I; 253 } 254 #ifdef BOOST_MSVC 255 #pragma warning(pop) 256 #endif 257 on_process_init()258 PVAPI_V on_process_init() 259 { 260 //Schedule on_thread_exit() to be called for the main 261 //thread before destructors of global objects have been 262 //called. 263 264 //It will not be run when 'quick' exiting the 265 //library; however, this is the standard behaviour 266 //for destructors of global objects, so that 267 //shouldn't be a problem. 268 269 atexit(boost::on_thread_exit); 270 271 //Call Boost process entry callback here 272 273 boost::on_process_enter(); 274 275 return INIRETSUCCESS_V; 276 } 277 on_process_term()278 PVAPI_V on_process_term() 279 { 280 boost::on_process_exit(); 281 return INIRETSUCCESS_V; 282 } 283 on_tls_callback(HINSTANCE,DWORD dwReason,PVOID)284 void NTAPI on_tls_callback(HINSTANCE /*h*/, DWORD dwReason, PVOID /*pv*/) 285 { 286 switch (dwReason) 287 { 288 case DLL_THREAD_DETACH: 289 boost::on_thread_exit(); 290 break; 291 } 292 } 293 294 #if (_MSC_VER >= 1500) dll_callback(HINSTANCE hInstance,DWORD dwReason,LPVOID lpReserved)295 BOOL WINAPI dll_callback(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) 296 #else 297 BOOL WINAPI dll_callback(HINSTANCE, DWORD dwReason, LPVOID) 298 #endif 299 { 300 switch (dwReason) 301 { 302 case DLL_THREAD_DETACH: 303 boost::on_thread_exit(); 304 break; 305 case DLL_PROCESS_DETACH: 306 boost::on_process_exit(); 307 break; 308 } 309 310 #if (_MSC_VER >= 1500) 311 if( _pRawDllMainOrig ) 312 { 313 return _pRawDllMainOrig(hInstance, dwReason, lpReserved); 314 } 315 #endif 316 return true; 317 } 318 } //namespace 319 320 extern "C" 321 { 322 extern BOOL (WINAPI * const _pRawDllMain)(HINSTANCE, DWORD, LPVOID)=&dll_callback; 323 } 324 namespace boost 325 { tss_cleanup_implemented()326 void tss_cleanup_implemented() 327 { 328 /* 329 This function's sole purpose is to cause a link error in cases where 330 automatic tss cleanup is not implemented by Boost.Threads as a 331 reminder that user code is responsible for calling the necessary 332 functions at the appropriate times (and for implementing an a 333 tss_cleanup_implemented() function to eliminate the linker's 334 missing symbol error). 335 336 If Boost.Threads later implements automatic tss cleanup in cases 337 where it currently doesn't (which is the plan), the duplicate 338 symbol error will warn the user that their custom solution is no 339 longer needed and can be removed. 340 */ 341 } 342 } 343 344 #endif //defined(_MSC_VER) && !defined(UNDER_CE) 345 346 #endif //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_LIB) 347