1 | // (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004. |
---|
2 | // Use, modification and distribution are subject to the |
---|
3 | // Boost Software License, Version 1.0. (See accompanying file |
---|
4 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
---|
5 | |
---|
6 | #include <boost/thread/detail/config.hpp> |
---|
7 | |
---|
8 | #if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && defined(_MSC_VER) |
---|
9 | |
---|
10 | #include <boost/thread/detail/tss_hooks.hpp> |
---|
11 | |
---|
12 | #include <stdlib.h> |
---|
13 | |
---|
14 | #define WIN32_LEAN_AND_MEAN |
---|
15 | #include <windows.h> |
---|
16 | |
---|
17 | //Definitions required by implementation |
---|
18 | |
---|
19 | #if (_MSC_VER < 1300) // 1300 == VC++ 7.0 |
---|
20 | typedef void (__cdecl *_PVFV)(void); |
---|
21 | #define INIRETSUCCESS |
---|
22 | #define PVAPI void |
---|
23 | #else |
---|
24 | typedef int (__cdecl *_PVFV)(void); |
---|
25 | #define INIRETSUCCESS 0 |
---|
26 | #define PVAPI int |
---|
27 | #endif |
---|
28 | |
---|
29 | typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID); |
---|
30 | |
---|
31 | //Symbols for connection to the runtime environment |
---|
32 | |
---|
33 | extern "C" |
---|
34 | { |
---|
35 | extern DWORD _tls_used; //the tls directory (located in .rdata segment) |
---|
36 | extern _TLSCB __xl_a[], __xl_z[]; //tls initializers */ |
---|
37 | } |
---|
38 | |
---|
39 | namespace |
---|
40 | { |
---|
41 | //Forward declarations |
---|
42 | |
---|
43 | static PVAPI on_tls_prepare(void); |
---|
44 | static PVAPI on_process_init(void); |
---|
45 | static PVAPI on_process_term(void); |
---|
46 | static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID); |
---|
47 | |
---|
48 | //The .CRT$Xxx information is taken from Codeguru: |
---|
49 | //http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/ |
---|
50 | |
---|
51 | #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 |
---|
52 | # pragma data_seg(push, old_seg) |
---|
53 | #endif |
---|
54 | //Callback to run tls glue code first. |
---|
55 | //I don't think it is necessary to run it |
---|
56 | //at .CRT$XIB level, since we are only |
---|
57 | //interested in thread detachement. But |
---|
58 | //this could be changed easily if required. |
---|
59 | |
---|
60 | #pragma data_seg(".CRT$XIU") |
---|
61 | static _PVFV p_tls_prepare = on_tls_prepare; |
---|
62 | #pragma data_seg() |
---|
63 | |
---|
64 | //Callback after all global ctors. |
---|
65 | |
---|
66 | #pragma data_seg(".CRT$XCU") |
---|
67 | static _PVFV p_process_init = on_process_init; |
---|
68 | #pragma data_seg() |
---|
69 | |
---|
70 | //Callback for tls notifications. |
---|
71 | |
---|
72 | #pragma data_seg(".CRT$XLB") |
---|
73 | _TLSCB p_thread_callback = on_tls_callback; |
---|
74 | #pragma data_seg() |
---|
75 | |
---|
76 | //Callback for termination. |
---|
77 | |
---|
78 | #pragma data_seg(".CRT$XTU") |
---|
79 | static _PVFV p_process_term = on_process_term; |
---|
80 | #pragma data_seg() |
---|
81 | #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 |
---|
82 | # pragma data_seg(pop, old_seg) |
---|
83 | #endif |
---|
84 | |
---|
85 | PVAPI on_tls_prepare(void) |
---|
86 | { |
---|
87 | //The following line has an important side effect: |
---|
88 | //if the TLS directory is not already there, it will |
---|
89 | //be created by the linker. In other words, it forces a tls |
---|
90 | //directory to be generated by the linker even when static tls |
---|
91 | //(i.e. __declspec(thread)) is not used. |
---|
92 | //The volatile should prevent the optimizer |
---|
93 | //from removing the reference. |
---|
94 | |
---|
95 | DWORD volatile dw = _tls_used; |
---|
96 | |
---|
97 | #if (_MSC_VER < 1300) // 1300 == VC++ 7.0 |
---|
98 | _TLSCB* pfbegin = __xl_a; |
---|
99 | _TLSCB* pfend = __xl_z; |
---|
100 | _TLSCB* pfdst = pfbegin; |
---|
101 | //pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks; |
---|
102 | |
---|
103 | //The following loop will merge the address pointers |
---|
104 | //into a contiguous area, since the tlssup code seems |
---|
105 | //to require this (at least on MSVC 6) |
---|
106 | |
---|
107 | while (pfbegin < pfend) |
---|
108 | { |
---|
109 | if (*pfbegin != 0) |
---|
110 | { |
---|
111 | *pfdst = *pfbegin; |
---|
112 | ++pfdst; |
---|
113 | } |
---|
114 | ++pfbegin; |
---|
115 | } |
---|
116 | |
---|
117 | *pfdst = 0; |
---|
118 | #endif |
---|
119 | |
---|
120 | return INIRETSUCCESS; |
---|
121 | } |
---|
122 | |
---|
123 | PVAPI on_process_init(void) |
---|
124 | { |
---|
125 | //Schedule on_thread_exit() to be called for the main |
---|
126 | //thread before destructors of global objects have been |
---|
127 | //called. |
---|
128 | |
---|
129 | //It will not be run when 'quick' exiting the |
---|
130 | //library; however, this is the standard behaviour |
---|
131 | //for destructors of global objects, so that |
---|
132 | //shouldn't be a problem. |
---|
133 | |
---|
134 | atexit(on_thread_exit); |
---|
135 | |
---|
136 | //Call Boost process entry callback here |
---|
137 | |
---|
138 | on_process_enter(); |
---|
139 | |
---|
140 | return INIRETSUCCESS; |
---|
141 | } |
---|
142 | |
---|
143 | PVAPI on_process_term(void) |
---|
144 | { |
---|
145 | on_process_exit(); |
---|
146 | return INIRETSUCCESS; |
---|
147 | } |
---|
148 | |
---|
149 | void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) |
---|
150 | { |
---|
151 | switch (dwReason) |
---|
152 | { |
---|
153 | case DLL_THREAD_DETACH: |
---|
154 | { |
---|
155 | on_thread_exit(); |
---|
156 | break; |
---|
157 | } |
---|
158 | } |
---|
159 | } |
---|
160 | } //namespace |
---|
161 | |
---|
162 | extern "C" void tss_cleanup_implemented(void) |
---|
163 | { |
---|
164 | /* |
---|
165 | This function's sole purpose is to cause a link error in cases where |
---|
166 | automatic tss cleanup is not implemented by Boost.Threads as a |
---|
167 | reminder that user code is responsible for calling the necessary |
---|
168 | functions at the appropriate times (and for implementing an a |
---|
169 | tss_cleanup_implemented() function to eliminate the linker's |
---|
170 | missing symbol error). |
---|
171 | |
---|
172 | If Boost.Threads later implements automatic tss cleanup in cases |
---|
173 | where it currently doesn't (which is the plan), the duplicate |
---|
174 | symbol error will warn the user that their custom solution is no |
---|
175 | longer needed and can be removed. |
---|
176 | */ |
---|
177 | } |
---|
178 | |
---|
179 | #endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) |
---|