2 * mono-tls.c: Low-level TLS support
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
7 * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
11 #include <mono/utils/mach-support.h>
16 * On all platforms we should be able to use either __thread or pthread/TlsGetValue.
17 * Certain platforms will support fast tls only when using one of the thread local
18 * storage backends. By default this is __thread if we have HAVE_KW_THREAD defined.
20 * By default all platforms will call into these native getters whenever they need
21 * to get a tls value. On certain platforms we can try to be faster than this and
22 * avoid the call. We call this fast tls and each platform defines its own way to
23 * achieve this. For this, a platform has to define MONO_ARCH_HAVE_INLINED_TLS,
24 * and provide alternative getters/setters for a MonoTlsKey. In order to have fast
25 * getter/setters, the platform has to declare a way to fetch an internal offset
26 * (MONO_THREAD_VAR_OFFSET) which is stored here, and in the arch specific file
27 * probe the system to see if we can use the offset initialized here. If these
28 * run-time checks don't succeed we just use the fallbacks.
30 * In case we would wish to provide fast inlined tls for aot code, we would need
31 * to be sure that, at run-time, these two platform checks would never fail
32 * otherwise the tls getter/setters that we emitted would not work. Normally,
33 * there is little incentive to support this since tls access is most common in
34 * wrappers and managed allocators, both of which are not aot-ed by default.
35 * So far, we never supported inlined fast tls on full-aot systems.
44 #if HAVE_TLS_MODEL_ATTR
46 #if defined(__PIC__) && !defined(PIC)
48 * Must be compiling -fPIE, for executables. Build PIC
49 * but with initial-exec.
50 * http://bugs.gentoo.org/show_bug.cgi?id=165547
53 #define PIC_INITIAL_EXEC
57 * Define this if you want a faster libmono, which cannot be loaded dynamically as a
60 //#define PIC_INITIAL_EXEC
64 #ifdef PIC_INITIAL_EXEC
65 #define MONO_TLS_FAST __attribute__((tls_model("initial-exec")))
67 #if defined (__powerpc__)
68 /* local dynamic requires a call to __tls_get_addr to look up the
69 TLS block address via the Dynamic Thread Vector. In this case Thread
70 Pointer relative offsets can't be used as this modules TLS was
71 allocated separately (none contiguoiusly) from the initial TLS
74 For now we will disable this. */
77 #define MONO_TLS_FAST __attribute__((tls_model("local-dynamic")))
83 #define MONO_TLS_FAST __attribute__((tls_model("local-exec")))
91 /* Runtime offset detection */
92 #if defined(TARGET_AMD64) && !defined(TARGET_MACH) && !defined(HOST_WIN32) /* __thread likely not tested on mac/win */
95 // This only works if libmono is linked into the application
96 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; __asm ("movq " #var "@GOTTPOFF(%%rip), %0" : "=r" (foo)); offset = foo; } while (0)
98 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; __asm ("movq $" #var "@TPOFF, %0" : "=r" (foo)); offset = foo; } while (0)
101 #elif defined(TARGET_X86) && !defined(TARGET_MACH) && !defined(HOST_WIN32) && defined(__GNUC__)
104 #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)
106 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("movl $" #var "@ntpoff, %0" : "=r" (offset))
109 #elif defined(TARGET_ARM64) && !defined(PIC)
111 #define MONO_THREAD_VAR_OFFSET(var,offset) \
112 __asm ( "mov %0, #0\n add %0, %0, #:tprel_hi12:" #var "\n add %0, %0, #:tprel_lo12_nc:" #var "\n" \
117 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
121 /* Tls variables for each MonoTlsKey */
123 static __thread gpointer mono_tls_thread MONO_TLS_FAST;
124 static __thread gpointer mono_tls_jit_tls MONO_TLS_FAST;
125 static __thread gpointer mono_tls_domain MONO_TLS_FAST;
126 static __thread gpointer mono_tls_lmf MONO_TLS_FAST;
127 static __thread gpointer mono_tls_sgen_thread_info MONO_TLS_FAST;
128 static __thread gpointer mono_tls_lmf_addr MONO_TLS_FAST;
132 #if defined(TARGET_AMD64) && (defined(TARGET_MACH) || defined(HOST_WIN32))
133 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
134 #elif defined(TARGET_X86) && (defined(TARGET_MACH) || defined(HOST_WIN32))
135 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
137 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
140 static MonoNativeTlsKey mono_tls_key_thread;
141 static MonoNativeTlsKey mono_tls_key_jit_tls;
142 static MonoNativeTlsKey mono_tls_key_domain;
143 static MonoNativeTlsKey mono_tls_key_lmf;
144 static MonoNativeTlsKey mono_tls_key_sgen_thread_info;
145 static MonoNativeTlsKey mono_tls_key_lmf_addr;
149 static gint32 tls_offsets [TLS_KEY_NUM];
152 #define MONO_TLS_GET_VALUE(tls_var,tls_key) (tls_var)
153 #define MONO_TLS_SET_VALUE(tls_var,tls_key,value) (tls_var = value)
155 #define MONO_TLS_GET_VALUE(tls_var,tls_key) (mono_native_tls_get_value (tls_key))
156 #define MONO_TLS_SET_VALUE(tls_var,tls_key,value) (mono_native_tls_set_value (tls_key, value))
160 mono_tls_init_gc_keys (void)
163 MONO_THREAD_VAR_OFFSET (mono_tls_sgen_thread_info, tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
165 mono_native_tls_alloc (&mono_tls_key_sgen_thread_info, NULL);
166 MONO_THREAD_VAR_OFFSET (mono_tls_key_sgen_thread_info, tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
171 mono_tls_init_runtime_keys (void)
174 MONO_THREAD_VAR_OFFSET (mono_tls_thread, tls_offsets [TLS_KEY_THREAD]);
175 MONO_THREAD_VAR_OFFSET (mono_tls_jit_tls, tls_offsets [TLS_KEY_JIT_TLS]);
176 MONO_THREAD_VAR_OFFSET (mono_tls_domain, tls_offsets [TLS_KEY_DOMAIN]);
177 MONO_THREAD_VAR_OFFSET (mono_tls_lmf, tls_offsets [TLS_KEY_LMF]);
178 MONO_THREAD_VAR_OFFSET (mono_tls_lmf_addr, tls_offsets [TLS_KEY_LMF_ADDR]);
180 mono_native_tls_alloc (&mono_tls_key_thread, NULL);
181 MONO_THREAD_VAR_OFFSET (mono_tls_key_thread, tls_offsets [TLS_KEY_THREAD]);
182 mono_native_tls_alloc (&mono_tls_key_jit_tls, NULL);
183 MONO_THREAD_VAR_OFFSET (mono_tls_key_jit_tls, tls_offsets [TLS_KEY_JIT_TLS]);
184 mono_native_tls_alloc (&mono_tls_key_domain, NULL);
185 MONO_THREAD_VAR_OFFSET (mono_tls_key_domain, tls_offsets [TLS_KEY_DOMAIN]);
186 mono_native_tls_alloc (&mono_tls_key_lmf, NULL);
187 MONO_THREAD_VAR_OFFSET (mono_tls_key_lmf, tls_offsets [TLS_KEY_LMF]);
188 mono_native_tls_alloc (&mono_tls_key_lmf_addr, NULL);
189 MONO_THREAD_VAR_OFFSET (mono_tls_key_lmf_addr, tls_offsets [TLS_KEY_LMF_ADDR]);
194 mono_tls_free_keys (void)
196 #ifndef USE_KW_THREAD
197 mono_native_tls_free (mono_tls_key_thread);
198 mono_native_tls_free (mono_tls_key_jit_tls);
199 mono_native_tls_free (mono_tls_key_domain);
200 mono_native_tls_free (mono_tls_key_lmf);
201 mono_native_tls_free (mono_tls_key_sgen_thread_info);
202 mono_native_tls_free (mono_tls_key_lmf_addr);
208 * Gets the tls offset associated with the key. This offset is set at key
209 * initialization (at runtime). Certain targets can implement computing
210 * this offset and using it at runtime for fast inlined tls access.
213 mono_tls_get_tls_offset (MonoTlsKey key)
215 g_assert (tls_offsets [key]);
216 return tls_offsets [key];
220 * Returns the getter (gpointer (*)(void)) for the mono tls key.
221 * Managed code will always get the value by calling this getter.
224 mono_tls_get_tls_getter (MonoTlsKey key, gboolean name)
228 return name ? (gpointer)"mono_tls_get_thread" : (gpointer)mono_tls_get_thread;
229 case TLS_KEY_JIT_TLS:
230 return name ? (gpointer)"mono_tls_get_jit_tls" : (gpointer)mono_tls_get_jit_tls;
232 return name ? (gpointer)"mono_tls_get_domain" : (gpointer)mono_tls_get_domain;
234 return name ? (gpointer)"mono_tls_get_lmf" : (gpointer)mono_tls_get_lmf;
235 case TLS_KEY_SGEN_THREAD_INFO:
236 return name ? (gpointer)"mono_tls_get_sgen_thread_info" : (gpointer)mono_tls_get_sgen_thread_info;
237 case TLS_KEY_LMF_ADDR:
238 return name ? (gpointer)"mono_tls_get_lmf_addr" : (gpointer)mono_tls_get_lmf_addr;
240 g_assert_not_reached ();
244 /* Returns the setter (void (*)(gpointer)) for the mono tls key */
246 mono_tls_get_tls_setter (MonoTlsKey key, gboolean name)
250 return name ? (gpointer)"mono_tls_set_thread" : (gpointer)mono_tls_set_thread;
251 case TLS_KEY_JIT_TLS:
252 return name ? (gpointer)"mono_tls_set_jit_tls" : (gpointer)mono_tls_set_jit_tls;
254 return name ? (gpointer)"mono_tls_set_domain" : (gpointer)mono_tls_set_domain;
256 return name ? (gpointer)"mono_tls_set_lmf" : (gpointer)mono_tls_set_lmf;
257 case TLS_KEY_SGEN_THREAD_INFO:
258 return name ? (gpointer)"mono_tls_set_sgen_thread_info" : (gpointer)mono_tls_set_sgen_thread_info;
259 case TLS_KEY_LMF_ADDR:
260 return name ? (gpointer)"mono_tls_set_lmf_addr" : (gpointer)mono_tls_set_lmf_addr;
262 g_assert_not_reached ();
267 mono_tls_get_tls_addr (MonoTlsKey key)
269 if (key == TLS_KEY_LMF) {
270 #if defined(USE_KW_THREAD)
271 return &mono_tls_lmf;
272 #elif defined(TARGET_MACH)
273 return mono_mach_get_tls_address_from_thread (pthread_self (), mono_tls_key_lmf);
276 /* Implement if we ever need for other targets/keys */
277 g_assert_not_reached ();
281 /* Getters for each tls key */
282 gpointer mono_tls_get_thread (void)
284 return MONO_TLS_GET_VALUE (mono_tls_thread, mono_tls_key_thread);
287 gpointer mono_tls_get_jit_tls (void)
289 return MONO_TLS_GET_VALUE (mono_tls_jit_tls, mono_tls_key_jit_tls);
292 gpointer mono_tls_get_domain (void)
294 return MONO_TLS_GET_VALUE (mono_tls_domain, mono_tls_key_domain);
297 gpointer mono_tls_get_lmf (void)
299 return MONO_TLS_GET_VALUE (mono_tls_lmf, mono_tls_key_lmf);
302 gpointer mono_tls_get_sgen_thread_info (void)
304 return MONO_TLS_GET_VALUE (mono_tls_sgen_thread_info, mono_tls_key_sgen_thread_info);
307 gpointer mono_tls_get_lmf_addr (void)
309 return MONO_TLS_GET_VALUE (mono_tls_lmf_addr, mono_tls_key_lmf_addr);
312 /* Setters for each tls key */
313 void mono_tls_set_thread (gpointer value)
315 MONO_TLS_SET_VALUE (mono_tls_thread, mono_tls_key_thread, value);
318 void mono_tls_set_jit_tls (gpointer value)
320 MONO_TLS_SET_VALUE (mono_tls_jit_tls, mono_tls_key_jit_tls, value);
323 void mono_tls_set_domain (gpointer value)
325 MONO_TLS_SET_VALUE (mono_tls_domain, mono_tls_key_domain, value);
328 void mono_tls_set_lmf (gpointer value)
330 MONO_TLS_SET_VALUE (mono_tls_lmf, mono_tls_key_lmf, value);
333 void mono_tls_set_sgen_thread_info (gpointer value)
335 MONO_TLS_SET_VALUE (mono_tls_sgen_thread_info, mono_tls_key_sgen_thread_info, value);
338 void mono_tls_set_lmf_addr (gpointer value)
340 MONO_TLS_SET_VALUE (mono_tls_lmf_addr, mono_tls_key_lmf_addr, value);