| /** | |
| * This file has no copyright assigned and is placed in the Public Domain. | |
| * This file is part of the mingw-w64 runtime package. | |
| * No warranty is given; refer to the file DISCLAIMER.PD within this package. | |
| */ | |
| #ifndef __MINGW_THREAD_LOCAL_H | |
| #define __MINGW_THREAD_LOCAL_H | |
| #include <windows.h> | |
| /* Macro __MINGW_ALLOC_THREAD_LOCAL allocates Windows native thread local | |
| * storage for variable of specified type with initial value at compile time | |
| * and returns pointer to that allocated thread local variable at runtime. | |
| * If the specified type is array then the returned value is also of the | |
| * array type, specifically "type[]" (and not the "type(*)[]"). | |
| * Its functionality is exactly ABI same as the MSVC __declspec(thread) keyword, | |
| * just it returns pointer to that variable (not variable itself) and it does | |
| * not require any thread local storage support from compiler. | |
| * | |
| * Note that Windows native thread local storage support is not available for | |
| * DLL libraries which were loaded at runtime by one of the LoadLibrary call | |
| * on systems prior Windows Vista. MSVC __declspec(thread) keyword and also | |
| * __MINGW_ALLOC_THREAD_LOCAL() macro for that case tries to dereference memory | |
| * which could belongs to other module which cause memory corruption or crash. | |
| * | |
| * To avoid these issues, there are two additional macros: | |
| * __MINGW_ALLOC_THREAD_LOCAL_OR_NULL and __MINGW_ALLOC_THREAD_LOCAL_OR_STATIC | |
| * If the thread local storage was not allocated by the system then the first | |
| * one returns NULL pointer, and second one returns pointer to static storage | |
| * allocated at the compile time (which is shared by all threads). So the | |
| * second one macro is useful for functions which should be thread-safe when | |
| * possible with fallback to non-thread-safe on pre-Vista systems. | |
| * | |
| * MinGW-w64 CRT runtime code sets _tls_index to -1 at compile time and Windows | |
| * system PE loader changes it at runtime to the correct TLS index/slot value, | |
| * which would not be -1. Value 0 is valid index/slot used by EXE binaries and | |
| * in some cases also by DLL libraries (if no other DLL library and also main | |
| * EXE does not use TLS). Note that we cannot use TLS callbacks for this check | |
| * because on some systems (e.g. on all Win9x) TLS callbacks are never called. | |
| * | |
| * Examples: | |
| * int *tls0 = __MINGW_ALLOC_THREAD_LOCAL(int); | |
| * int *tls1 = __MINGW_ALLOC_THREAD_LOCAL(int, = 10); | |
| * int *tls2 = __MINGW_ALLOC_THREAD_LOCAL(int[4]); | |
| * int *tls3 = __MINGW_ALLOC_THREAD_LOCAL(int[4], = {1,2,3,4}); | |
| * int *tls4 = __MINGW_ALLOC_THREAD_LOCAL(int[], = {1,2,3,4}); | |
| */ | |
| #define ___MINGW_DEREF_IF_ARRAY(var, expr) \ | |
| __builtin_choose_expr( \ | |
| __builtin_classify_type(var) == 5 && !__builtin_types_compatible_p( \ | |
| __typeof__(&*__builtin_choose_expr(__builtin_classify_type(var) == 5, (var), NULL)), \ | |
| __typeof__(var) \ | |
| ), \ | |
| *(expr), \ | |
| (expr) \ | |
| ) | |
| #define ___MINGW_ALLOC_THREAD_LOCAL_HELPER(fallback, type, ...) ({ \ | |
| extern char *_tls_start; \ | |
| extern unsigned long _tls_index; \ | |
| __attribute__((__section__(".tls$"))) static __typeof__(type) __mingw_tls_var __VA_ARGS__; \ | |
| ___MINGW_DEREF_IF_ARRAY(__mingw_tls_var, \ | |
| ((__builtin_constant_p(fallback) && (fallback) == (__typeof__(type) *)-1) || _tls_index != (unsigned long)-1) ? \ | |
| (__typeof__(type) *)(((char ***)NtCurrentTeb())[11][_tls_index] + ((char *)&__mingw_tls_var - (char *)&_tls_start)) : \ | |
| (fallback) \ | |
| ); \ | |
| }) | |
| #define __MINGW_ALLOC_THREAD_LOCAL(type, ...) ___MINGW_ALLOC_THREAD_LOCAL_HELPER((__typeof__(type) *)-1, type, ##__VA_ARGS__) | |
| #define __MINGW_ALLOC_THREAD_LOCAL_OR_NULL(type, ...) ___MINGW_ALLOC_THREAD_LOCAL_HELPER((__typeof__(type) *)NULL, type, ##__VA_ARGS__) | |
| #define __MINGW_ALLOC_THREAD_LOCAL_OR_STATIC(type, ...) ___MINGW_ALLOC_THREAD_LOCAL_HELPER(&__mingw_tls_var, type, ##__VA_ARGS__) | |
| #endif |