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