[sdks] Bump Android NDK, build tools and platform tools versions
[mono-project.git] / mono / utils / mono-tls.c
bloba4cee8256678c5c91802866e57295bf8750cbdb6
1 /**
2 * \file
3 * Low-level TLS support
5 * Thread local variables that are accessed both from native and managed code
6 * are defined here and should be accessed only through this APIs
8 * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
9 */
11 #include <mono/utils/mach-support.h>
13 #include "mono-tls.h"
16 * On all platforms we should be able to use either __thread or __declspec (thread)
17 * or pthread/TlsGetValue.
18 * Certain platforms will support fast tls only when using one of the thread local
19 * storage backends. By default this is __thread if we have MONO_KEYWORD_THREAD defined.
21 * By default all platforms will call into these native getters whenever they need
22 * to get a tls value. On certain platforms we can try to be faster than this and
23 * avoid the call. We call this fast tls and each platform defines its own way to
24 * achieve this. For this, a platform has to define MONO_ARCH_HAVE_INLINED_TLS,
25 * and provide alternative getters/setters for a MonoTlsKey. In order to have fast
26 * getter/setters, the platform has to declare a way to fetch an internal offset
27 * (MONO_THREAD_VAR_OFFSET) which is stored here, and in the arch specific file
28 * probe the system to see if we can use the offset initialized here. If these
29 * run-time checks don't succeed we just use the fallbacks.
31 * In case we would wish to provide fast inlined tls for aot code, we would need
32 * to be sure that, at run-time, these two platform checks would never fail
33 * otherwise the tls getter/setters that we emitted would not work. Normally,
34 * there is little incentive to support this since tls access is most common in
35 * wrappers and managed allocators, both of which are not aot-ed by default.
36 * So far, we never supported inlined fast tls on full-aot systems.
39 #ifdef MONO_KEYWORD_THREAD
41 /* tls attribute */
42 #if HAVE_TLS_MODEL_ATTR
44 #if defined(__PIC__) && !defined(PIC)
46 * Must be compiling -fPIE, for executables. Build PIC
47 * but with initial-exec.
48 * http://bugs.gentoo.org/show_bug.cgi?id=165547
50 #define PIC
51 #define PIC_INITIAL_EXEC
52 #endif
55 * Define this if you want a faster libmono, which cannot be loaded dynamically as a
56 * module.
58 //#define PIC_INITIAL_EXEC
60 #if defined(PIC)
62 #ifdef PIC_INITIAL_EXEC
63 #define MONO_TLS_FAST __attribute__ ((__tls_model__("initial-exec")))
64 #else
65 #if defined (__powerpc__)
66 /* local dynamic requires a call to __tls_get_addr to look up the
67 TLS block address via the Dynamic Thread Vector. In this case Thread
68 Pointer relative offsets can't be used as this modules TLS was
69 allocated separately (none contiguoiusly) from the initial TLS
70 block.
72 For now we will disable this. */
73 #define MONO_TLS_FAST
74 #else
75 #define MONO_TLS_FAST __attribute__ ((__tls_model__("local-dynamic")))
76 #endif
77 #endif
79 #else
81 #define MONO_TLS_FAST __attribute__ ((__tls_model__("local-exec")))
83 #endif
85 #else
86 #define MONO_TLS_FAST
87 #endif
89 /* Runtime offset detection */
90 #if defined(TARGET_AMD64) && !defined(TARGET_MACH) && !defined(HOST_WIN32) /* __thread likely not tested on mac/win */
92 #if defined(PIC)
93 // This only works if libmono is linked into the application
94 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; __asm ("movq " #var "@GOTTPOFF(%%rip), %0" : "=r" (foo)); offset = foo; } while (0)
95 #else
96 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; __asm ("movq $" #var "@TPOFF, %0" : "=r" (foo)); offset = foo; } while (0)
97 #endif
99 #elif defined(TARGET_X86) && !defined(TARGET_MACH) && !defined(HOST_WIN32) && defined(__GNUC__)
101 #if defined(PIC)
102 #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)
103 #else
104 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("movl $" #var "@ntpoff, %0" : "=r" (offset))
105 #endif
107 #elif defined(TARGET_ARM64) && !defined(PIC)
109 #define MONO_THREAD_VAR_OFFSET(var,offset) \
110 __asm ( "mov %0, #0\n add %0, %0, #:tprel_hi12:" #var "\n add %0, %0, #:tprel_lo12_nc:" #var "\n" \
111 : "=r" (offset))
113 #elif defined(TARGET_ARM) && defined(__ARM_EABI__) && !defined(PIC)
115 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm (" ldr %0, 1f; b 2f; 1: .word " #var "(tpoff); 2:" : "=r" (offset))
117 #elif defined(TARGET_S390X)
118 # if defined(__PIC__)
119 # if !defined(__PIE__)
120 // This only works if libmono is linked into the application
121 # define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; \
122 void *x = &var; \
123 __asm__ ("ear %%r1,%%a0\n" \
124 "sllg %%r1,%%r1,32\n" \
125 "ear %%r1,%%a1\n" \
126 "lgr %0,%1\n" \
127 "sgr %0,%%r1\n" \
128 : "=r" (foo) : "r" (x) \
129 : "1", "cc"); \
130 offset = foo; } while (0)
131 # elif __PIE__ == 1
132 # define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; \
133 __asm__ ("lg %0," #var "@GOTNTPOFF(%%r12)\n\t" \
134 : "=r" (foo)); \
135 offset = foo; } while (0)
136 # elif __PIE__ == 2
137 # define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; \
138 __asm__ ("larl %%r1," #var "@INDNTPOFF\n\t" \
139 "lg %0,0(%%r1)\n\t" \
140 : "=r" (foo) : \
141 : "1", "cc"); \
142 offset = foo; } while (0)
143 # endif
144 # else
145 # define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; \
146 __asm__ ("basr %%r1,0\n\t" \
147 "j 0f\n\t" \
148 ".quad " #var "@NTPOFF\n" \
149 "0:\n\t" \
150 "lg %0,4(%%r1)\n\t" \
151 : "=r" (foo) : : "1"); \
152 offset = foo; } while (0)
153 # endif
155 #elif defined (TARGET_RISCV) && !defined (PIC)
157 #define MONO_THREAD_VAR_OFFSET(var, offset) \
158 do { \
159 guint32 temp; \
160 __asm__ ( \
161 "lui %0, %%tprel_hi(" #var ")\n" \
162 "add %0, %0, tp, %%tprel_add(" #var ")\n" \
163 "addi %0, %0, %%tprel_lo(" #var ")\n" \
164 : "=r" (temp) \
165 ); \
166 offset = temp; \
167 } while (0)
169 #else
171 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
173 #endif
175 #ifdef __cplusplus
176 // static and anonymous namespace both fail to link otherwise; Linux/amd64/gcc.
177 #define MONO_TLS_STATIC /* nothing */
178 #else
179 #define MONO_TLS_STATIC static
180 #endif
182 /* Tls variables for each MonoTlsKey */
183 MONO_TLS_STATIC MONO_KEYWORD_THREAD MonoInternalThread *mono_tls_thread MONO_TLS_FAST;
184 MONO_TLS_STATIC MONO_KEYWORD_THREAD MonoJitTlsData *mono_tls_jit_tls MONO_TLS_FAST;
185 MONO_TLS_STATIC MONO_KEYWORD_THREAD MonoDomain *mono_tls_domain MONO_TLS_FAST;
186 MONO_TLS_STATIC MONO_KEYWORD_THREAD SgenThreadInfo *mono_tls_sgen_thread_info MONO_TLS_FAST;
187 MONO_TLS_STATIC MONO_KEYWORD_THREAD MonoLMF **mono_tls_lmf_addr MONO_TLS_FAST;
189 #undef MONO_TLS_STATIC // no further uses
191 #else
193 #if defined(TARGET_AMD64) && (defined(TARGET_MACH) || defined(HOST_WIN32))
194 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
195 #elif defined(TARGET_X86) && (defined(TARGET_MACH) || defined(HOST_WIN32))
196 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
197 #else
198 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
199 #endif
201 static MonoNativeTlsKey mono_tls_key_thread;
202 static MonoNativeTlsKey mono_tls_key_jit_tls;
203 static MonoNativeTlsKey mono_tls_key_domain;
204 static MonoNativeTlsKey mono_tls_key_sgen_thread_info;
205 static MonoNativeTlsKey mono_tls_key_lmf_addr;
207 #endif
209 static gint32 tls_offsets [TLS_KEY_NUM];
211 #ifdef MONO_KEYWORD_THREAD
212 #define MONO_TLS_GET_VALUE(tls_var,tls_key) (tls_var)
213 #define MONO_TLS_SET_VALUE(tls_var,tls_key,value) (tls_var = value)
214 #else
215 #define MONO_TLS_GET_VALUE(tls_var,tls_key) (mono_native_tls_get_value (tls_key))
216 #define MONO_TLS_SET_VALUE(tls_var,tls_key,value) (mono_native_tls_set_value (tls_key, value))
217 #endif
219 void
220 mono_tls_init_gc_keys (void)
222 #ifdef MONO_KEYWORD_THREAD
223 MONO_THREAD_VAR_OFFSET (mono_tls_sgen_thread_info, tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
224 #else
225 mono_native_tls_alloc (&mono_tls_key_sgen_thread_info, NULL);
226 MONO_THREAD_VAR_OFFSET (mono_tls_key_sgen_thread_info, tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
227 #endif
230 void
231 mono_tls_init_runtime_keys (void)
233 #ifdef MONO_KEYWORD_THREAD
234 MONO_THREAD_VAR_OFFSET (mono_tls_thread, tls_offsets [TLS_KEY_THREAD]);
235 MONO_THREAD_VAR_OFFSET (mono_tls_jit_tls, tls_offsets [TLS_KEY_JIT_TLS]);
236 MONO_THREAD_VAR_OFFSET (mono_tls_domain, tls_offsets [TLS_KEY_DOMAIN]);
237 MONO_THREAD_VAR_OFFSET (mono_tls_lmf_addr, tls_offsets [TLS_KEY_LMF_ADDR]);
238 #else
239 mono_native_tls_alloc (&mono_tls_key_thread, NULL);
240 MONO_THREAD_VAR_OFFSET (mono_tls_key_thread, tls_offsets [TLS_KEY_THREAD]);
241 mono_native_tls_alloc (&mono_tls_key_jit_tls, NULL);
242 MONO_THREAD_VAR_OFFSET (mono_tls_key_jit_tls, tls_offsets [TLS_KEY_JIT_TLS]);
243 mono_native_tls_alloc (&mono_tls_key_domain, NULL);
244 MONO_THREAD_VAR_OFFSET (mono_tls_key_domain, tls_offsets [TLS_KEY_DOMAIN]);
245 mono_native_tls_alloc (&mono_tls_key_lmf_addr, NULL);
246 MONO_THREAD_VAR_OFFSET (mono_tls_key_lmf_addr, tls_offsets [TLS_KEY_LMF_ADDR]);
247 #endif
250 void
251 mono_tls_free_keys (void)
253 #ifndef MONO_KEYWORD_THREAD
254 mono_native_tls_free (mono_tls_key_thread);
255 mono_native_tls_free (mono_tls_key_jit_tls);
256 mono_native_tls_free (mono_tls_key_domain);
257 mono_native_tls_free (mono_tls_key_sgen_thread_info);
258 mono_native_tls_free (mono_tls_key_lmf_addr);
259 #endif
264 * Gets the tls offset associated with the key. This offset is set at key
265 * initialization (at runtime). Certain targets can implement computing
266 * this offset and using it at runtime for fast inlined tls access.
268 gint32
269 mono_tls_get_tls_offset (MonoTlsKey key)
271 g_assert (tls_offsets [key]);
272 return tls_offsets [key];
276 * Returns the getter (gpointer (*)(void)) for the mono tls key.
277 * Managed code will always get the value by calling this getter.
279 MonoTlsGetter
280 mono_tls_get_tls_getter (MonoTlsKey key)
282 switch (key) {
283 case TLS_KEY_THREAD:
284 return (MonoTlsGetter)mono_tls_get_thread;
285 case TLS_KEY_JIT_TLS:
286 return (MonoTlsGetter)mono_tls_get_jit_tls;
287 case TLS_KEY_DOMAIN:
288 return (MonoTlsGetter)mono_tls_get_domain;
289 case TLS_KEY_SGEN_THREAD_INFO:
290 return (MonoTlsGetter)mono_tls_get_sgen_thread_info;
291 case TLS_KEY_LMF_ADDR:
292 return (MonoTlsGetter)mono_tls_get_lmf_addr;
294 g_assert_not_reached ();
295 return NULL;
298 /* Returns the setter (void (*)(gpointer)) for the mono tls key */
299 MonoTlsSetter
300 mono_tls_get_tls_setter (MonoTlsKey key)
302 switch (key) {
303 case TLS_KEY_THREAD:
304 return (MonoTlsSetter)mono_tls_set_thread;
305 case TLS_KEY_JIT_TLS:
306 return (MonoTlsSetter)mono_tls_set_jit_tls;
307 case TLS_KEY_DOMAIN:
308 return (MonoTlsSetter)mono_tls_set_domain;
309 case TLS_KEY_SGEN_THREAD_INFO:
310 return (MonoTlsSetter)mono_tls_set_sgen_thread_info;
311 case TLS_KEY_LMF_ADDR:
312 return (MonoTlsSetter)mono_tls_set_lmf_addr;
314 g_assert_not_reached ();
315 return NULL;
318 // Casts on getters are for the !MONO_KEYWORD_THREAD case.
320 /* Getters for each tls key */
321 MonoInternalThread *mono_tls_get_thread (void)
323 return (MonoInternalThread*)MONO_TLS_GET_VALUE (mono_tls_thread, mono_tls_key_thread);
326 MonoJitTlsData *mono_tls_get_jit_tls (void)
328 return (MonoJitTlsData*)MONO_TLS_GET_VALUE (mono_tls_jit_tls, mono_tls_key_jit_tls);
331 MonoDomain *mono_tls_get_domain (void)
333 return (MonoDomain*)MONO_TLS_GET_VALUE (mono_tls_domain, mono_tls_key_domain);
336 SgenThreadInfo *mono_tls_get_sgen_thread_info (void)
338 return (SgenThreadInfo*)MONO_TLS_GET_VALUE (mono_tls_sgen_thread_info, mono_tls_key_sgen_thread_info);
341 MonoLMF **mono_tls_get_lmf_addr (void)
343 return (MonoLMF**)MONO_TLS_GET_VALUE (mono_tls_lmf_addr, mono_tls_key_lmf_addr);
346 /* Setters for each tls key */
347 void mono_tls_set_thread (MonoInternalThread *value)
349 MONO_TLS_SET_VALUE (mono_tls_thread, mono_tls_key_thread, value);
352 void mono_tls_set_jit_tls (MonoJitTlsData *value)
354 MONO_TLS_SET_VALUE (mono_tls_jit_tls, mono_tls_key_jit_tls, value);
357 void mono_tls_set_domain (MonoDomain *value)
359 MONO_TLS_SET_VALUE (mono_tls_domain, mono_tls_key_domain, value);
362 void mono_tls_set_sgen_thread_info (SgenThreadInfo *value)
364 MONO_TLS_SET_VALUE (mono_tls_sgen_thread_info, mono_tls_key_sgen_thread_info, value);
367 void mono_tls_set_lmf_addr (MonoLMF **value)
369 MONO_TLS_SET_VALUE (mono_tls_lmf_addr, mono_tls_key_lmf_addr, value);