1*ef84fd3bSjoerg /* ===---------- emutls.c - Implements __emutls_get_address ---------------===
2*ef84fd3bSjoerg *
3*ef84fd3bSjoerg * The LLVM Compiler Infrastructure
4*ef84fd3bSjoerg *
5*ef84fd3bSjoerg * This file is dual licensed under the MIT and the University of Illinois Open
6*ef84fd3bSjoerg * Source Licenses. See LICENSE.TXT for details.
7*ef84fd3bSjoerg *
8*ef84fd3bSjoerg * ===----------------------------------------------------------------------===
9*ef84fd3bSjoerg */
10*ef84fd3bSjoerg #include <pthread.h>
11*ef84fd3bSjoerg #include <stdint.h>
12*ef84fd3bSjoerg #include <stdlib.h>
13*ef84fd3bSjoerg #include <string.h>
14*ef84fd3bSjoerg
15*ef84fd3bSjoerg #include "int_lib.h"
16*ef84fd3bSjoerg #include "int_util.h"
17*ef84fd3bSjoerg
18*ef84fd3bSjoerg /* Default is not to use posix_memalign, so systems like Android
19*ef84fd3bSjoerg * can use thread local data without heavier POSIX memory allocators.
20*ef84fd3bSjoerg */
21*ef84fd3bSjoerg #ifndef EMUTLS_USE_POSIX_MEMALIGN
22*ef84fd3bSjoerg #define EMUTLS_USE_POSIX_MEMALIGN 0
23*ef84fd3bSjoerg #endif
24*ef84fd3bSjoerg
25*ef84fd3bSjoerg /* For every TLS variable xyz,
26*ef84fd3bSjoerg * there is one __emutls_control variable named __emutls_v.xyz.
27*ef84fd3bSjoerg * If xyz has non-zero initial value, __emutls_v.xyz's "value"
28*ef84fd3bSjoerg * will point to __emutls_t.xyz, which has the initial value.
29*ef84fd3bSjoerg */
30*ef84fd3bSjoerg typedef struct __emutls_control {
31*ef84fd3bSjoerg size_t size; /* size of the object in bytes */
32*ef84fd3bSjoerg size_t align; /* alignment of the object in bytes */
33*ef84fd3bSjoerg union {
34*ef84fd3bSjoerg uintptr_t index; /* data[index-1] is the object address */
35*ef84fd3bSjoerg void* address; /* object address, when in single thread env */
36*ef84fd3bSjoerg } object;
37*ef84fd3bSjoerg void* value; /* null or non-zero initial value for the object */
38*ef84fd3bSjoerg } __emutls_control;
39*ef84fd3bSjoerg
emutls_memalign_alloc(size_t align,size_t size)40*ef84fd3bSjoerg static __inline void *emutls_memalign_alloc(size_t align, size_t size) {
41*ef84fd3bSjoerg void *base;
42*ef84fd3bSjoerg #if EMUTLS_USE_POSIX_MEMALIGN
43*ef84fd3bSjoerg if (posix_memalign(&base, align, size) != 0)
44*ef84fd3bSjoerg abort();
45*ef84fd3bSjoerg #else
46*ef84fd3bSjoerg #define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*))
47*ef84fd3bSjoerg char* object;
48*ef84fd3bSjoerg if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
49*ef84fd3bSjoerg abort();
50*ef84fd3bSjoerg base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES))
51*ef84fd3bSjoerg & ~(uintptr_t)(align - 1));
52*ef84fd3bSjoerg
53*ef84fd3bSjoerg ((void**)base)[-1] = object;
54*ef84fd3bSjoerg #endif
55*ef84fd3bSjoerg return base;
56*ef84fd3bSjoerg }
57*ef84fd3bSjoerg
emutls_memalign_free(void * base)58*ef84fd3bSjoerg static __inline void emutls_memalign_free(void *base) {
59*ef84fd3bSjoerg #if EMUTLS_USE_POSIX_MEMALIGN
60*ef84fd3bSjoerg free(base);
61*ef84fd3bSjoerg #else
62*ef84fd3bSjoerg /* The mallocated address is in ((void**)base)[-1] */
63*ef84fd3bSjoerg free(((void**)base)[-1]);
64*ef84fd3bSjoerg #endif
65*ef84fd3bSjoerg }
66*ef84fd3bSjoerg
67*ef84fd3bSjoerg /* Emulated TLS objects are always allocated at run-time. */
emutls_allocate_object(__emutls_control * control)68*ef84fd3bSjoerg static __inline void *emutls_allocate_object(__emutls_control *control) {
69*ef84fd3bSjoerg /* Use standard C types, check with gcc's emutls.o. */
70*ef84fd3bSjoerg typedef unsigned int gcc_word __attribute__((mode(word)));
71*ef84fd3bSjoerg typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
72*ef84fd3bSjoerg COMPILE_TIME_ASSERT(sizeof(size_t) == sizeof(gcc_word));
73*ef84fd3bSjoerg COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer));
74*ef84fd3bSjoerg COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*));
75*ef84fd3bSjoerg
76*ef84fd3bSjoerg size_t size = control->size;
77*ef84fd3bSjoerg size_t align = control->align;
78*ef84fd3bSjoerg if (align < sizeof(void*))
79*ef84fd3bSjoerg align = sizeof(void*);
80*ef84fd3bSjoerg /* Make sure that align is power of 2. */
81*ef84fd3bSjoerg if ((align & (align - 1)) != 0)
82*ef84fd3bSjoerg abort();
83*ef84fd3bSjoerg
84*ef84fd3bSjoerg void* base = emutls_memalign_alloc(align, size);
85*ef84fd3bSjoerg if (control->value)
86*ef84fd3bSjoerg memcpy(base, control->value, size);
87*ef84fd3bSjoerg else
88*ef84fd3bSjoerg memset(base, 0, size);
89*ef84fd3bSjoerg return base;
90*ef84fd3bSjoerg }
91*ef84fd3bSjoerg
92*ef84fd3bSjoerg static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
93*ef84fd3bSjoerg
94*ef84fd3bSjoerg static size_t emutls_num_object = 0; /* number of allocated TLS objects */
95*ef84fd3bSjoerg
96*ef84fd3bSjoerg typedef struct emutls_address_array {
97*ef84fd3bSjoerg uintptr_t size; /* number of elements in the 'data' array */
98*ef84fd3bSjoerg void* data[];
99*ef84fd3bSjoerg } emutls_address_array;
100*ef84fd3bSjoerg
101*ef84fd3bSjoerg static pthread_key_t emutls_pthread_key;
102*ef84fd3bSjoerg
emutls_key_destructor(void * ptr)103*ef84fd3bSjoerg static void emutls_key_destructor(void* ptr) {
104*ef84fd3bSjoerg emutls_address_array* array = (emutls_address_array*)ptr;
105*ef84fd3bSjoerg uintptr_t i;
106*ef84fd3bSjoerg for (i = 0; i < array->size; ++i) {
107*ef84fd3bSjoerg if (array->data[i])
108*ef84fd3bSjoerg emutls_memalign_free(array->data[i]);
109*ef84fd3bSjoerg }
110*ef84fd3bSjoerg free(ptr);
111*ef84fd3bSjoerg }
112*ef84fd3bSjoerg
emutls_init(void)113*ef84fd3bSjoerg static void emutls_init(void) {
114*ef84fd3bSjoerg if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
115*ef84fd3bSjoerg abort();
116*ef84fd3bSjoerg }
117*ef84fd3bSjoerg
118*ef84fd3bSjoerg /* Returns control->object.index; set index if not allocated yet. */
emutls_get_index(__emutls_control * control)119*ef84fd3bSjoerg static __inline uintptr_t emutls_get_index(__emutls_control *control) {
120*ef84fd3bSjoerg uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE);
121*ef84fd3bSjoerg if (!index) {
122*ef84fd3bSjoerg static pthread_once_t once = PTHREAD_ONCE_INIT;
123*ef84fd3bSjoerg pthread_once(&once, emutls_init);
124*ef84fd3bSjoerg pthread_mutex_lock(&emutls_mutex);
125*ef84fd3bSjoerg index = control->object.index;
126*ef84fd3bSjoerg if (!index) {
127*ef84fd3bSjoerg index = ++emutls_num_object;
128*ef84fd3bSjoerg __atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE);
129*ef84fd3bSjoerg }
130*ef84fd3bSjoerg pthread_mutex_unlock(&emutls_mutex);
131*ef84fd3bSjoerg }
132*ef84fd3bSjoerg return index;
133*ef84fd3bSjoerg }
134*ef84fd3bSjoerg
135*ef84fd3bSjoerg /* Updates newly allocated thread local emutls_address_array. */
emutls_check_array_set_size(emutls_address_array * array,uintptr_t size)136*ef84fd3bSjoerg static __inline void emutls_check_array_set_size(emutls_address_array *array,
137*ef84fd3bSjoerg uintptr_t size) {
138*ef84fd3bSjoerg if (array == NULL)
139*ef84fd3bSjoerg abort();
140*ef84fd3bSjoerg array->size = size;
141*ef84fd3bSjoerg pthread_setspecific(emutls_pthread_key, (void*)array);
142*ef84fd3bSjoerg }
143*ef84fd3bSjoerg
144*ef84fd3bSjoerg /* Returns the new 'data' array size, number of elements,
145*ef84fd3bSjoerg * which must be no smaller than the given index.
146*ef84fd3bSjoerg */
emutls_new_data_array_size(uintptr_t index)147*ef84fd3bSjoerg static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) {
148*ef84fd3bSjoerg /* Need to allocate emutls_address_array with one extra slot
149*ef84fd3bSjoerg * to store the data array size.
150*ef84fd3bSjoerg * Round up the emutls_address_array size to multiple of 16.
151*ef84fd3bSjoerg */
152*ef84fd3bSjoerg return ((index + 1 + 15) & ~((uintptr_t)15)) - 1;
153*ef84fd3bSjoerg }
154*ef84fd3bSjoerg
155*ef84fd3bSjoerg /* Returns the thread local emutls_address_array.
156*ef84fd3bSjoerg * Extends its size if necessary to hold address at index.
157*ef84fd3bSjoerg */
158*ef84fd3bSjoerg static __inline emutls_address_array *
emutls_get_address_array(uintptr_t index)159*ef84fd3bSjoerg emutls_get_address_array(uintptr_t index) {
160*ef84fd3bSjoerg emutls_address_array* array = pthread_getspecific(emutls_pthread_key);
161*ef84fd3bSjoerg if (array == NULL) {
162*ef84fd3bSjoerg uintptr_t new_size = emutls_new_data_array_size(index);
163*ef84fd3bSjoerg array = calloc(new_size + 1, sizeof(void*));
164*ef84fd3bSjoerg emutls_check_array_set_size(array, new_size);
165*ef84fd3bSjoerg } else if (index > array->size) {
166*ef84fd3bSjoerg uintptr_t orig_size = array->size;
167*ef84fd3bSjoerg uintptr_t new_size = emutls_new_data_array_size(index);
168*ef84fd3bSjoerg array = realloc(array, (new_size + 1) * sizeof(void*));
169*ef84fd3bSjoerg if (array)
170*ef84fd3bSjoerg memset(array->data + orig_size, 0,
171*ef84fd3bSjoerg (new_size - orig_size) * sizeof(void*));
172*ef84fd3bSjoerg emutls_check_array_set_size(array, new_size);
173*ef84fd3bSjoerg }
174*ef84fd3bSjoerg return array;
175*ef84fd3bSjoerg }
176*ef84fd3bSjoerg
__emutls_get_address(__emutls_control * control)177*ef84fd3bSjoerg void* __emutls_get_address(__emutls_control* control) {
178*ef84fd3bSjoerg uintptr_t index = emutls_get_index(control);
179*ef84fd3bSjoerg emutls_address_array* array = emutls_get_address_array(index);
180*ef84fd3bSjoerg if (array->data[index - 1] == NULL)
181*ef84fd3bSjoerg array->data[index - 1] = emutls_allocate_object(control);
182*ef84fd3bSjoerg return array->data[index - 1];
183*ef84fd3bSjoerg }
184