Imported Upstream version 1.49.0
[platform/upstream/boost.git] / libs / thread / src / win32 / tss_pe.cpp
1 // $Id: tss_pe.cpp 72431 2011-06-06 08:28:31Z anthonyw $
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/thread/detail/config.hpp>
11
12 #if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) 
13
14 #if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__)
15
16 #include <boost/thread/detail/tss_hooks.hpp>
17
18 #include <windows.h>
19
20 #include <cstdlib>
21
22 namespace boost
23 {
24     void tss_cleanup_implemented() {}
25 }
26
27 namespace {
28     void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv)
29     {
30         switch (dwReason)
31         {
32         case DLL_THREAD_DETACH:
33         {
34             boost::on_thread_exit();
35             break;
36         }
37         }
38     }
39 }
40
41 #if defined(__MINGW64__) || (__MINGW32_MAJOR_VERSION >3) ||             \
42     ((__MINGW32_MAJOR_VERSION==3) && (__MINGW32_MINOR_VERSION>=18))
43 extern "C"
44 {
45     PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
46 }
47 #else
48 extern "C" {
49
50     void (* after_ctors )() __attribute__((section(".ctors")))     = boost::on_process_enter;
51     void (* before_dtors)() __attribute__((section(".dtors")))     = boost::on_thread_exit;
52     void (* after_dtors )() __attribute__((section(".dtors.zzz"))) = boost::on_process_exit;
53
54     ULONG __tls_index__ = 0;
55     char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
56     char __tls_start__ __attribute__((section(".tls"))) = 0;
57
58
59     PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0;
60     PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0;
61 }
62 extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) =
63 {
64         (DWORD) &__tls_start__,
65         (DWORD) &__tls_end__,
66         (DWORD) &__tls_index__,
67         (DWORD) (&__crt_xl_start__+1),
68         (DWORD) 0,
69         (DWORD) 0
70 };
71 #endif
72
73
74 #elif  defined(_MSC_VER) && !defined(UNDER_CE)
75
76     #include <boost/thread/detail/tss_hooks.hpp>
77
78     #include <stdlib.h>
79
80     #define WIN32_LEAN_AND_MEAN
81     #include <windows.h>
82
83     //Definitions required by implementation
84
85     #if (_MSC_VER < 1300) // 1300 == VC++ 7.0
86         typedef void (__cdecl *_PVFV)();
87         #define INIRETSUCCESS
88         #define PVAPI void __cdecl
89     #else
90         typedef int (__cdecl *_PVFV)();
91         #define INIRETSUCCESS 0
92         #define PVAPI int __cdecl
93     #endif
94
95     typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);
96
97     //Symbols for connection to the runtime environment
98
99     extern "C"
100     {
101         extern DWORD _tls_used; //the tls directory (located in .rdata segment)
102         extern _TLSCB __xl_a[], __xl_z[];    //tls initializers */
103     }
104
105     namespace
106     {
107         //Forward declarations
108
109         static PVAPI on_tls_prepare();
110         static PVAPI on_process_init();
111         static PVAPI on_process_term();
112         static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID);
113
114         //The .CRT$Xxx information is taken from Codeguru:
115         //http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
116
117 #if (_MSC_VER >= 1400)
118 #pragma section(".CRT$XIU",long,read)
119 #pragma section(".CRT$XCU",long,read)
120 #pragma section(".CRT$XTU",long,read)
121 #pragma section(".CRT$XLC",long,read)
122         __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
123         __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
124         __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
125         __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
126 #else
127         #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
128         #   pragma data_seg(push, old_seg)
129         #endif
130             //Callback to run tls glue code first.
131             //I don't think it is necessary to run it
132             //at .CRT$XIB level, since we are only
133             //interested in thread detachement. But
134             //this could be changed easily if required.
135
136             #pragma data_seg(".CRT$XIU")
137             static _PVFV p_tls_prepare = on_tls_prepare;
138             #pragma data_seg()
139
140             //Callback after all global ctors.
141
142             #pragma data_seg(".CRT$XCU")
143             static _PVFV p_process_init = on_process_init;
144             #pragma data_seg()
145
146             //Callback for tls notifications.
147
148             #pragma data_seg(".CRT$XLB")
149             _TLSCB p_thread_callback = on_tls_callback;
150             #pragma data_seg()
151             //Callback for termination.
152
153             #pragma data_seg(".CRT$XTU")
154             static _PVFV p_process_term = on_process_term;
155             #pragma data_seg()
156         #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
157         #   pragma data_seg(pop, old_seg)
158         #endif
159 #endif
160
161 #ifdef BOOST_MSVC
162 #pragma warning(push)
163 #pragma warning(disable:4189)
164 #endif
165
166         PVAPI on_tls_prepare()
167         {
168             //The following line has an important side effect:
169             //if the TLS directory is not already there, it will
170             //be created by the linker. In other words, it forces a tls
171             //directory to be generated by the linker even when static tls
172             //(i.e. __declspec(thread)) is not used.
173             //The volatile should prevent the optimizer
174             //from removing the reference.
175
176             DWORD volatile dw = _tls_used;
177
178             #if (_MSC_VER < 1300) // 1300 == VC++ 7.0
179                 _TLSCB* pfbegin = __xl_a;
180                 _TLSCB* pfend = __xl_z;
181                 _TLSCB* pfdst = pfbegin;
182                 //pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks;
183
184                 //The following loop will merge the address pointers
185                 //into a contiguous area, since the tlssup code seems
186                 //to require this (at least on MSVC 6)
187
188                 while (pfbegin < pfend)
189                 {
190                     if (*pfbegin != 0)
191                     {
192                         *pfdst = *pfbegin;
193                         ++pfdst;
194                     }
195                     ++pfbegin;
196                 }
197
198                 *pfdst = 0;
199             #endif
200
201             return INIRETSUCCESS;
202         }
203 #ifdef BOOST_MSVC
204 #pragma warning(pop)
205 #endif
206
207         PVAPI on_process_init()
208         {
209             //Schedule on_thread_exit() to be called for the main
210             //thread before destructors of global objects have been
211             //called.
212
213             //It will not be run when 'quick' exiting the
214             //library; however, this is the standard behaviour
215             //for destructors of global objects, so that
216             //shouldn't be a problem.
217
218             atexit(boost::on_thread_exit);
219
220             //Call Boost process entry callback here
221
222             boost::on_process_enter();
223
224             return INIRETSUCCESS;
225         }
226
227         PVAPI on_process_term()
228         {
229             boost::on_process_exit();
230             return INIRETSUCCESS;
231         }
232
233         void NTAPI on_tls_callback(HINSTANCE /*h*/, DWORD dwReason, PVOID /*pv*/)
234         {
235             switch (dwReason)
236             {
237             case DLL_THREAD_DETACH:
238                 boost::on_thread_exit();
239                 break;
240             }
241         }
242
243         BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID)
244         {
245             switch (dwReason)
246             {
247             case DLL_THREAD_DETACH:
248                 boost::on_thread_exit();
249                 break;
250             case DLL_PROCESS_DETACH:
251                 boost::on_process_exit();
252                 break;
253             }
254             return true;
255         }
256     } //namespace
257
258 extern "C"
259 {
260     extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback;
261 }
262 namespace boost
263 {
264     void tss_cleanup_implemented()
265     {
266         /*
267         This function's sole purpose is to cause a link error in cases where
268         automatic tss cleanup is not implemented by Boost.Threads as a
269         reminder that user code is responsible for calling the necessary
270         functions at the appropriate times (and for implementing an a
271         tss_cleanup_implemented() function to eliminate the linker's
272         missing symbol error).
273
274         If Boost.Threads later implements automatic tss cleanup in cases
275         where it currently doesn't (which is the plan), the duplicate
276         symbol error will warn the user that their custom solution is no
277         longer needed and can be removed.
278         */
279     }
280 }
281
282 #endif //defined(_MSC_VER) && !defined(UNDER_CE)
283
284 #endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)