xref: /reactos/sdk/lib/crt/startup/tlssup.c (revision 682f85ad)
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 int __mingw_usemthread_dll;
85 #endif
86 
87 BOOL WINAPI __dyn_tls_init (HANDLE, DWORD, LPVOID);
88 
89 BOOL WINAPI
90 __dyn_tls_init (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
91 {
92   _PVFV *pfunc;
93   uintptr_t ps;
94 
95   /* We don't let us trick here.  */
96   if (_CRT_MT != 2)
97    _CRT_MT = 2;
98 
99   if (dwReason != DLL_THREAD_ATTACH)
100     {
101       if (dwReason == DLL_PROCESS_ATTACH)
102         __mingw_TLScallback (hDllHandle, dwReason, lpreserved);
103       return TRUE;
104     }
105 
106   ps = (uintptr_t) &__xd_a;
107   ps += sizeof (uintptr_t);
108   for ( ; ps != (uintptr_t) &__xd_z; ps += sizeof (uintptr_t))
109     {
110       pfunc = (_PVFV *) ps;
111       if (*pfunc != NULL)
112 	(*pfunc)();
113     }
114   return TRUE;
115 }
116 
117 const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback = (const PIMAGE_TLS_CALLBACK) __dyn_tls_init;
118 _CRTALLOC(".CRT$XLC") PIMAGE_TLS_CALLBACK __xl_c = (PIMAGE_TLS_CALLBACK) __dyn_tls_init;
119 
120 int __cdecl __tlregdtor (_PVFV);
121 
122 int __cdecl
123 __tlregdtor (_PVFV func)
124 {
125   if (!func)
126     return 0;
127 #if !defined (DISABLE_MS_TLS)
128   if (dtor_list == NULL)
129     {
130       dtor_list = &dtor_list_head;
131       dtor_list_head.count = 0;
132     }
133     else if (dtor_list->count == FUNCS_PER_NODE)
134     {
135       TlsDtorNode *pnode = (TlsDtorNode *) malloc (sizeof (TlsDtorNode));
136       if (pnode == NULL)
137 	return -1;
138       pnode->count = 0;
139       pnode->next = dtor_list;
140       dtor_list = pnode;
141 
142       dtor_list->count = 0;
143     }
144   dtor_list->funcs[dtor_list->count++] = func;
145 #endif
146   return 0;
147 }
148 
149 static BOOL WINAPI
150 __dyn_tls_dtor (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
151 {
152 #if !defined (DISABLE_MS_TLS)
153   TlsDtorNode *pnode, *pnext;
154   int i;
155 #endif
156 
157   if (dwReason != DLL_THREAD_DETACH && dwReason != DLL_PROCESS_DETACH)
158     return TRUE;
159   /* As TLS variables are detroyed already by DLL_THREAD_DETACH
160      call, we have to avoid access on the possible DLL_PROCESS_DETACH
161      call the already destroyed TLS vars.
162      TODO: The used local thread based variables have to be handled
163      manually, so that we can control their lifetime here.  */
164 #if !defined (DISABLE_MS_TLS)
165   if (dwReason != DLL_PROCESS_DETACH)
166     {
167       for (pnode = dtor_list; pnode != NULL; pnode = pnext)
168         {
169           for (i = pnode->count - 1; i >= 0; --i)
170 	    {
171 	      if (pnode->funcs[i] != NULL)
172 	        (*pnode->funcs[i])();
173 	    }
174           pnext = pnode->next;
175           if (pnext != NULL)
176 	    free ((void *) pnode);
177         }
178     }
179 #endif
180   __mingw_TLScallback (hDllHandle, dwReason, lpreserved);
181   return TRUE;
182 }
183 
184 _CRTALLOC(".CRT$XLD") PIMAGE_TLS_CALLBACK __xl_d = (PIMAGE_TLS_CALLBACK) __dyn_tls_dtor;
185 
186 
187 int mingw_initltsdrot_force = 0;
188 int mingw_initltsdyn_force = 0;
189 int mingw_initltssuo_force = 0;
190