[msvc] Update csproj files
[mono.git] / mono / utils / mono-tls.c
1 /*
2  * mono-tls.c: Low-level TLS support
3  *
4  * Thread local variables that are accessed both from native and managed code
5  * are defined here and should be accessed only through this APIs
6  *
7  * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
8  */
9
10 #include <mono/utils/mach-support.h>
11
12 #include "mono-tls.h"
13
14 /*
15  * On all platforms we should be able to use either __thread or pthread/TlsGetValue.
16  * Certain platforms will support fast tls only when using one of the thread local
17  * storage backends. By default this is __thread if we have HAVE_KW_THREAD defined.
18  *
19  * By default all platforms will call into these native getters whenever they need
20  * to get a tls value. On certain platforms we can try to be faster than this and
21  * avoid the call. We call this fast tls and each platform defines its own way to
22  * achieve this. For this, a platform has to define MONO_ARCH_HAVE_INLINED_TLS,
23  * and provide alternative getters/setters for a MonoTlsKey. In order to have fast
24  * getter/setters, the platform has to declare a way to fetch an internal offset
25  * (MONO_THREAD_VAR_OFFSET) which is stored here, and in the arch specific file
26  * probe the system to see if we can use the offset initialized here. If these
27  * run-time checks don't succeed we just use the fallbacks.
28  *
29  * In case we would wish to provide fast inlined tls for aot code, we would need
30  * to be sure that, at run-time, these two platform checks would never fail
31  * otherwise the tls getter/setters that we emitted would not work. Normally,
32  * there is little incentive to support this since tls access is most common in
33  * wrappers and managed allocators, both of which are not aot-ed by default.
34  * So far, we never supported inlined fast tls on full-aot systems.
35  */
36
37 #ifdef USE_KW_THREAD
38
39 /* tls attribute */
40 #if HAVE_TLS_MODEL_ATTR
41
42 #if defined(__PIC__) && !defined(PIC)
43 /*
44  * Must be compiling -fPIE, for executables.  Build PIC
45  * but with initial-exec.
46  * http://bugs.gentoo.org/show_bug.cgi?id=165547
47  */
48 #define PIC
49 #define PIC_INITIAL_EXEC
50 #endif
51
52 /*
53  * Define this if you want a faster libmono, which cannot be loaded dynamically as a
54  * module.
55  */
56 //#define PIC_INITIAL_EXEC
57
58 #if defined(PIC)
59
60 #ifdef PIC_INITIAL_EXEC
61 #define MONO_TLS_FAST __attribute__ ((__tls_model__("initial-exec")))
62 #else
63 #if defined (__powerpc__)
64 /* local dynamic requires a call to __tls_get_addr to look up the
65    TLS block address via the Dynamic Thread Vector. In this case Thread
66    Pointer relative offsets can't be used as this modules TLS was
67    allocated separately (none contiguoiusly) from the initial TLS
68    block.
69
70    For now we will disable this. */
71 #define MONO_TLS_FAST
72 #else
73 #define MONO_TLS_FAST __attribute__ ((__tls_model__("local-dynamic")))
74 #endif
75 #endif
76
77 #else
78
79 #define MONO_TLS_FAST __attribute__ ((__tls_model__("local-exec")))
80
81 #endif
82
83 #else
84 #define MONO_TLS_FAST
85 #endif
86
87 /* Runtime offset detection */
88 #if defined(TARGET_AMD64) && !defined(TARGET_MACH) && !defined(HOST_WIN32) /* __thread likely not tested on mac/win */
89
90 #if defined(PIC)
91 // This only works if libmono is linked into the application
92 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;  __asm ("movq " #var "@GOTTPOFF(%%rip), %0" : "=r" (foo)); offset = foo; } while (0)
93 #else
94 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;  __asm ("movq $" #var "@TPOFF, %0" : "=r" (foo)); offset = foo; } while (0)
95 #endif
96
97 #elif defined(TARGET_X86) && !defined(TARGET_MACH) && !defined(HOST_WIN32) && defined(__GNUC__)
98
99 #if defined(PIC)
100 #define MONO_THREAD_VAR_OFFSET(var,offset) do { int tmp; __asm ("call 1f; 1: popl %0; addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %0; movl " #var "@gotntpoff(%0), %1" : "=r" (tmp), "=r" (offset)); } while (0)
101 #else
102 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("movl $" #var "@ntpoff, %0" : "=r" (offset))
103 #endif
104
105 #elif defined(TARGET_ARM64) && !defined(PIC)
106
107 #define MONO_THREAD_VAR_OFFSET(var,offset) \
108         __asm ( "mov %0, #0\n add %0, %0, #:tprel_hi12:" #var "\n add %0, %0, #:tprel_lo12_nc:" #var "\n" \
109                 : "=r" (offset))
110
111 #elif defined(TARGET_ARM) && defined(__ARM_EABI__) && !defined(PIC)
112
113 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("     ldr     %0, 1f; b 2f; 1: .word " #var "(tpoff); 2:" : "=r" (offset))
114
115 #elif defined(TARGET_S390X)
116 # if defined(__PIC__)
117 #  if !defined(__PIE__)
118 // This only works if libmono is linked into the application
119 #   define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                                 \
120                                                 __asm__ ("basr  %%r1,0\n\t"                     \
121                                                          "j     0f\n\t"                         \
122                                                          ".quad " #var "@TLSGD\n"               \
123                                                          "0:\n\t"                               \
124                                                          "lg    %%r2,4(%%r1)\n\t"               \
125                                                          "brasl %%r14,__tls_get_offset@PLT:tls_gdcall:"#var"\n\t" \
126                                                          "lgr   %0,%%r2\n\t"                    \
127                                                         : "=r" (foo) :                          \
128                                                         : "1", "2", "14", "cc");                \
129                                                 offset = foo; } while (0)
130 #  elif __PIE__ == 1
131 #   define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                                         \
132                                                 __asm__ ("lg    %0," #var "@GOTNTPOFF(%%r12)\n\t"       \
133                                                          : "=r" (foo));                                 \
134                                                 offset = foo; } while (0)
135 #  elif __PIE__ == 2
136 #   define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                                 \
137                                                 __asm__ ("larl  %%r1," #var "@INDNTPOFF\n\t"    \
138                                                          "lg    %0,0(%%r1)\n\t"                 \
139                                                          : "=r" (foo) :                         \
140                                                          : "1", "cc");                          \
141                                                 offset = foo; } while (0)
142 #  endif
143 # else
144 #  define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                          \
145                                                 __asm__ ("basr  %%r1,0\n\t"             \
146                                                          "j     0f\n\t"                 \
147                                                          ".quad " #var "@NTPOFF\n"      \
148                                                          "0:\n\t"                       \
149                                                          "lg    %0,4(%%r1)\n\t"         \
150                                                         : "=r" (foo) : : "1");          \
151                                                 offset = foo; } while (0)
152 # endif
153 #else
154
155 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
156
157 #endif
158
159 /* Tls variables for each MonoTlsKey */
160
161 static __thread gpointer mono_tls_thread MONO_TLS_FAST;
162 static __thread gpointer mono_tls_jit_tls MONO_TLS_FAST;
163 static __thread gpointer mono_tls_domain MONO_TLS_FAST;
164 static __thread gpointer mono_tls_lmf MONO_TLS_FAST;
165 static __thread gpointer mono_tls_sgen_thread_info MONO_TLS_FAST;
166 static __thread gpointer mono_tls_lmf_addr MONO_TLS_FAST;
167
168 #else
169
170 #if defined(TARGET_AMD64) && (defined(TARGET_MACH) || defined(HOST_WIN32))
171 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
172 #elif defined(TARGET_X86) && (defined(TARGET_MACH) || defined(HOST_WIN32))
173 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
174 #else
175 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
176 #endif
177
178 static MonoNativeTlsKey mono_tls_key_thread;
179 static MonoNativeTlsKey mono_tls_key_jit_tls;
180 static MonoNativeTlsKey mono_tls_key_domain;
181 static MonoNativeTlsKey mono_tls_key_sgen_thread_info;
182 static MonoNativeTlsKey mono_tls_key_lmf_addr;
183
184 #endif
185
186 static gint32 tls_offsets [TLS_KEY_NUM];
187
188 #ifdef USE_KW_THREAD
189 #define MONO_TLS_GET_VALUE(tls_var,tls_key) (tls_var)
190 #define MONO_TLS_SET_VALUE(tls_var,tls_key,value) (tls_var = value)
191 #else
192 #define MONO_TLS_GET_VALUE(tls_var,tls_key) (mono_native_tls_get_value (tls_key))
193 #define MONO_TLS_SET_VALUE(tls_var,tls_key,value) (mono_native_tls_set_value (tls_key, value))
194 #endif
195
196 void
197 mono_tls_init_gc_keys (void)
198 {
199 #ifdef USE_KW_THREAD
200         MONO_THREAD_VAR_OFFSET (mono_tls_sgen_thread_info, tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
201 #else
202         mono_native_tls_alloc (&mono_tls_key_sgen_thread_info, NULL);
203         MONO_THREAD_VAR_OFFSET (mono_tls_key_sgen_thread_info, tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
204 #endif
205 }
206
207 void
208 mono_tls_init_runtime_keys (void)
209 {
210 #ifdef USE_KW_THREAD
211         MONO_THREAD_VAR_OFFSET (mono_tls_thread, tls_offsets [TLS_KEY_THREAD]);
212         MONO_THREAD_VAR_OFFSET (mono_tls_jit_tls, tls_offsets [TLS_KEY_JIT_TLS]);
213         MONO_THREAD_VAR_OFFSET (mono_tls_domain, tls_offsets [TLS_KEY_DOMAIN]);
214         MONO_THREAD_VAR_OFFSET (mono_tls_lmf_addr, tls_offsets [TLS_KEY_LMF_ADDR]);
215 #else
216         mono_native_tls_alloc (&mono_tls_key_thread, NULL);
217         MONO_THREAD_VAR_OFFSET (mono_tls_key_thread, tls_offsets [TLS_KEY_THREAD]);
218         mono_native_tls_alloc (&mono_tls_key_jit_tls, NULL);
219         MONO_THREAD_VAR_OFFSET (mono_tls_key_jit_tls, tls_offsets [TLS_KEY_JIT_TLS]);
220         mono_native_tls_alloc (&mono_tls_key_domain, NULL);
221         MONO_THREAD_VAR_OFFSET (mono_tls_key_domain, tls_offsets [TLS_KEY_DOMAIN]);
222         mono_native_tls_alloc (&mono_tls_key_lmf_addr, NULL);
223         MONO_THREAD_VAR_OFFSET (mono_tls_key_lmf_addr, tls_offsets [TLS_KEY_LMF_ADDR]);
224 #endif
225 }
226
227 void
228 mono_tls_free_keys (void)
229 {
230 #ifndef USE_KW_THREAD
231         mono_native_tls_free (mono_tls_key_thread);
232         mono_native_tls_free (mono_tls_key_jit_tls);
233         mono_native_tls_free (mono_tls_key_domain);
234         mono_native_tls_free (mono_tls_key_sgen_thread_info);
235         mono_native_tls_free (mono_tls_key_lmf_addr);
236 #endif
237 }
238
239
240 /*
241  * Gets the tls offset associated with the key. This offset is set at key
242  * initialization (at runtime). Certain targets can implement computing
243  * this offset and using it at runtime for fast inlined tls access.
244  */
245 gint32
246 mono_tls_get_tls_offset (MonoTlsKey key)
247 {
248         g_assert (tls_offsets [key]);
249         return tls_offsets [key];
250 }
251
252 /*
253  * Returns the getter (gpointer (*)(void)) for the mono tls key.
254  * Managed code will always get the value by calling this getter.
255  */
256 gpointer
257 mono_tls_get_tls_getter (MonoTlsKey key, gboolean name)
258 {
259         switch (key) {
260         case TLS_KEY_THREAD:
261                 return name ? (gpointer)"mono_tls_get_thread" : (gpointer)mono_tls_get_thread;
262         case TLS_KEY_JIT_TLS:
263                 return name ? (gpointer)"mono_tls_get_jit_tls" : (gpointer)mono_tls_get_jit_tls;
264         case TLS_KEY_DOMAIN:
265                 return name ? (gpointer)"mono_tls_get_domain" : (gpointer)mono_tls_get_domain;
266         case TLS_KEY_SGEN_THREAD_INFO:
267                 return name ? (gpointer)"mono_tls_get_sgen_thread_info" : (gpointer)mono_tls_get_sgen_thread_info;
268         case TLS_KEY_LMF_ADDR:
269                 return name ? (gpointer)"mono_tls_get_lmf_addr" : (gpointer)mono_tls_get_lmf_addr;
270         }
271         g_assert_not_reached ();
272         return NULL;
273 }
274
275 /* Returns the setter (void (*)(gpointer)) for the mono tls key */
276 gpointer
277 mono_tls_get_tls_setter (MonoTlsKey key, gboolean name)
278 {
279         switch (key) {
280         case TLS_KEY_THREAD:
281                 return name ? (gpointer)"mono_tls_set_thread" : (gpointer)mono_tls_set_thread;
282         case TLS_KEY_JIT_TLS:
283                 return name ? (gpointer)"mono_tls_set_jit_tls" : (gpointer)mono_tls_set_jit_tls;
284         case TLS_KEY_DOMAIN:
285                 return name ? (gpointer)"mono_tls_set_domain" : (gpointer)mono_tls_set_domain;
286         case TLS_KEY_SGEN_THREAD_INFO:
287                 return name ? (gpointer)"mono_tls_set_sgen_thread_info" : (gpointer)mono_tls_set_sgen_thread_info;
288         case TLS_KEY_LMF_ADDR:
289                 return name ? (gpointer)"mono_tls_set_lmf_addr" : (gpointer)mono_tls_set_lmf_addr;
290         }
291         g_assert_not_reached ();
292         return NULL;
293 }
294
295 /* Getters for each tls key */
296 gpointer mono_tls_get_thread (void)
297 {
298         return MONO_TLS_GET_VALUE (mono_tls_thread, mono_tls_key_thread);
299 }
300
301 gpointer mono_tls_get_jit_tls (void)
302 {
303         return MONO_TLS_GET_VALUE (mono_tls_jit_tls, mono_tls_key_jit_tls);
304 }
305
306 gpointer mono_tls_get_domain (void)
307 {
308         return MONO_TLS_GET_VALUE (mono_tls_domain, mono_tls_key_domain);
309 }
310
311 gpointer mono_tls_get_sgen_thread_info (void)
312 {
313         return MONO_TLS_GET_VALUE (mono_tls_sgen_thread_info, mono_tls_key_sgen_thread_info);
314 }
315
316 gpointer mono_tls_get_lmf_addr (void)
317 {
318         return MONO_TLS_GET_VALUE (mono_tls_lmf_addr, mono_tls_key_lmf_addr);
319 }
320
321 /* Setters for each tls key */
322 void mono_tls_set_thread (gpointer value)
323 {
324         MONO_TLS_SET_VALUE (mono_tls_thread, mono_tls_key_thread, value);
325 }
326
327 void mono_tls_set_jit_tls (gpointer value)
328 {
329         MONO_TLS_SET_VALUE (mono_tls_jit_tls, mono_tls_key_jit_tls, value);
330 }
331
332 void mono_tls_set_domain (gpointer value)
333 {
334         MONO_TLS_SET_VALUE (mono_tls_domain, mono_tls_key_domain, value);
335 }
336
337 void mono_tls_set_sgen_thread_info (gpointer value)
338 {
339         MONO_TLS_SET_VALUE (mono_tls_sgen_thread_info, mono_tls_key_sgen_thread_info, value);
340 }
341
342 void mono_tls_set_lmf_addr (gpointer value)
343 {
344         MONO_TLS_SET_VALUE (mono_tls_lmf_addr, mono_tls_key_lmf_addr, value);
345 }