- Update to r53061
[reactos.git] / lib / 3rdparty / mingw / tlssup.c
1 /**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the w64 mingw-runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 *
6 * Written by Kai Tietz <kai.tietz@onevision.com>
7 */
8
9 #ifdef CRTDLL
10 #undef CRTDLL
11 #endif
12
13 #include <sect_attribs.h>
14
15 #ifndef WIN32_LEAN_AND_MEAN
16 #define WIN32_LEAN_AND_MEAN
17 #endif
18 #include <windows.h>
19
20 #include <stdio.h>
21 #include <memory.h>
22 #include <malloc.h>
23 #ifndef _WIN64
24 #include <stdlib.h> /* for _winmajor */
25 #endif
26
27 #ifndef __INTERNAL_FUNC_DEFINED
28 #define __INTERNAL_FUNC_DEFINED
29 typedef void (__cdecl *_PVFV)(void);
30 typedef int (__cdecl *_PIFV)(void);
31 typedef void (__cdecl *_PVFI)(int);
32 #endif
33
34 extern WINBOOL __mingw_TLScallback (HANDLE hDllHandle, DWORD reason, LPVOID reserved);
35
36 #define FUNCS_PER_NODE 30
37
38 typedef struct TlsDtorNode {
39 int count;
40 struct TlsDtorNode *next;
41 _PVFV funcs[FUNCS_PER_NODE];
42 } TlsDtorNode;
43
44 ULONG _tls_index = 0;
45
46 /* TLS raw template data start and end. */
47 _CRTALLOC(".tls$AAA") char _tls_start = 0;
48 _CRTALLOC(".tls$ZZZ") char _tls_end = 0;
49
50 _CRTALLOC(".CRT$XLA") PIMAGE_TLS_CALLBACK __xl_a = 0;
51 _CRTALLOC(".CRT$XLZ") PIMAGE_TLS_CALLBACK __xl_z = 0;
52
53 #ifdef _WIN64
54 _CRTALLOC(".tls") const IMAGE_TLS_DIRECTORY64 _tls_used = {
55 (ULONGLONG) &_tls_start+1, (ULONGLONG) &_tls_end, (ULONGLONG) &_tls_index,
56 (ULONGLONG) (&__xl_a+1), (ULONG) 0, (ULONG) 0
57 };
58 #else
59 _CRTALLOC(".tls") const IMAGE_TLS_DIRECTORY _tls_used = {
60 (ULONG)(ULONG_PTR) &_tls_start+1, (ULONG)(ULONG_PTR) &_tls_end,
61 (ULONG)(ULONG_PTR) &_tls_index, (ULONG)(ULONG_PTR) (&__xl_a+1),
62 (ULONG) 0, (ULONG) 0
63 };
64 #endif
65
66 #ifndef __CRT_THREAD
67 #ifdef HAVE_ATTRIBUTE_THREAD
68 #define __CRT_THREAD __declspec(thread)
69 #else
70 #define __CRT_THREAD __thread
71 #endif
72 #endif
73
74 #define DISABLE_MS_TLS 1
75
76 static _CRTALLOC(".CRT$XDA") _PVFV __xd_a = 0;
77 static _CRTALLOC(".CRT$XDZ") _PVFV __xd_z = 0;
78
79 #if !defined (DISABLE_MS_TLS)
80 static __CRT_THREAD TlsDtorNode *dtor_list;
81 static __CRT_THREAD TlsDtorNode dtor_list_head;
82 #endif
83
84 extern int _CRT_MT;
85
86 #ifndef _WIN64
87 #define MINGWM10_DLL "mingwm10.dll"
88 typedef int (*fMTRemoveKeyDtor)(DWORD key);
89 typedef int (*fMTKeyDtor)(DWORD key, void (*dtor)(void *));
90 fMTRemoveKeyDtor __mingw_gMTRemoveKeyDtor;
91 fMTKeyDtor __mingw_gMTKeyDtor;
92 int __mingw_usemthread_dll;
93 static HANDLE __mingw_mthread_hdll;
94 #endif
95
96 BOOL WINAPI __dyn_tls_init (HANDLE, DWORD, LPVOID);
97
98 BOOL WINAPI
99 __dyn_tls_init (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
100 {
101 _PVFV *pfunc;
102 uintptr_t ps;
103
104 #ifndef _WIN64
105 if (_winmajor < 4)
106 {
107 __mingw_usemthread_dll = 1;
108 __mingw_mthread_hdll = LoadLibrary (MINGWM10_DLL);
109 if (__mingw_mthread_hdll != NULL)
110 {
111 __mingw_gMTRemoveKeyDtor = (fMTRemoveKeyDtor) GetProcAddress (__mingw_mthread_hdll, "__mingwthr_remove_key_dtor");
112 __mingw_gMTKeyDtor = (fMTKeyDtor) GetProcAddress (__mingw_mthread_hdll, "__mingwthr_key_dtor");
113 }
114 if (__mingw_mthread_hdll == NULL || !__mingw_gMTRemoveKeyDtor || !__mingw_gMTKeyDtor)
115 {
116 __mingw_gMTKeyDtor = NULL;
117 __mingw_gMTRemoveKeyDtor = NULL;
118 if (__mingw_mthread_hdll)
119 FreeLibrary (__mingw_mthread_hdll);
120 __mingw_mthread_hdll = NULL;
121 _CRT_MT = 0;
122 return TRUE;
123 }
124 _CRT_MT = 1;
125 return TRUE;
126 }
127 #endif
128 /* We don't let us trick here. */
129 if (_CRT_MT != 2)
130 _CRT_MT = 2;
131
132 if (dwReason != DLL_THREAD_ATTACH)
133 {
134 if (dwReason == DLL_PROCESS_ATTACH)
135 __mingw_TLScallback (hDllHandle, dwReason, lpreserved);
136 return TRUE;
137 }
138
139 ps = (uintptr_t) &__xd_a;
140 ps += sizeof (uintptr_t);
141 for ( ; ps != (uintptr_t) &__xd_z; ps += sizeof (uintptr_t))
142 {
143 pfunc = (_PVFV *) ps;
144 if (*pfunc != NULL)
145 (*pfunc)();
146 }
147 return TRUE;
148 }
149
150 const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback = (const PIMAGE_TLS_CALLBACK) __dyn_tls_init;
151 _CRTALLOC(".CRT$XLC") PIMAGE_TLS_CALLBACK __xl_c = (PIMAGE_TLS_CALLBACK) __dyn_tls_init;
152
153 int __cdecl __tlregdtor (_PVFV);
154
155 int __cdecl
156 __tlregdtor (_PVFV func)
157 {
158 if (!func)
159 return 0;
160 #if !defined (DISABLE_MS_TLS)
161 if (dtor_list == NULL)
162 {
163 dtor_list = &dtor_list_head;
164 dtor_list_head.count = 0;
165 }
166 else if (dtor_list->count == FUNCS_PER_NODE)
167 {
168 TlsDtorNode *pnode = (TlsDtorNode *) malloc (sizeof (TlsDtorNode));
169 if (pnode == NULL)
170 return -1;
171 pnode->count = 0;
172 pnode->next = dtor_list;
173 dtor_list = pnode;
174
175 dtor_list->count = 0;
176 }
177 dtor_list->funcs[dtor_list->count++] = func;
178 #endif
179 return 0;
180 }
181
182 static BOOL WINAPI
183 __dyn_tls_dtor (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
184 {
185 #if !defined (DISABLE_MS_TLS)
186 TlsDtorNode *pnode, *pnext;
187 int i;
188 #endif
189
190 if (dwReason != DLL_THREAD_DETACH && dwReason != DLL_PROCESS_DETACH)
191 return TRUE;
192 /* As TLS variables are detroyed already by DLL_THREAD_DETACH
193 call, we have to avoid access on the possible DLL_PROCESS_DETACH
194 call the already destroyed TLS vars.
195 TODO: The used local thread based variables have to be handled
196 manually, so that we can control their lifetime here. */
197 #if !defined (DISABLE_MS_TLS)
198 if (dwReason != DLL_PROCESS_DETACH)
199 {
200 for (pnode = dtor_list; pnode != NULL; pnode = pnext)
201 {
202 for (i = pnode->count - 1; i >= 0; --i)
203 {
204 if (pnode->funcs[i] != NULL)
205 (*pnode->funcs[i])();
206 }
207 pnext = pnode->next;
208 if (pnext != NULL)
209 free ((void *) pnode);
210 }
211 }
212 #endif
213 __mingw_TLScallback (hDllHandle, dwReason, lpreserved);
214 return TRUE;
215 }
216
217 _CRTALLOC(".CRT$XLD") PIMAGE_TLS_CALLBACK __xl_d = (PIMAGE_TLS_CALLBACK) __dyn_tls_dtor;
218
219
220 int mingw_initltsdrot_force = 0;
221 int mingw_initltsdyn_force = 0;
222 int mingw_initltssuo_force = 0;