• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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