1*38fd1498Szrj /* TLS emulation.
2*38fd1498Szrj Copyright (C) 2006-2018 Free Software Foundation, Inc.
3*38fd1498Szrj Contributed by Jakub Jelinek <jakub@redhat.com>.
4*38fd1498Szrj
5*38fd1498Szrj This file is part of GCC.
6*38fd1498Szrj
7*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
8*38fd1498Szrj the terms of the GNU General Public License as published by the Free
9*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
10*38fd1498Szrj version.
11*38fd1498Szrj
12*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
14*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15*38fd1498Szrj for more details.
16*38fd1498Szrj
17*38fd1498Szrj Under Section 7 of GPL version 3, you are granted additional
18*38fd1498Szrj permissions described in the GCC Runtime Library Exception, version
19*38fd1498Szrj 3.1, as published by the Free Software Foundation.
20*38fd1498Szrj
21*38fd1498Szrj You should have received a copy of the GNU General Public License and
22*38fd1498Szrj a copy of the GCC Runtime Library Exception along with this program;
23*38fd1498Szrj see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24*38fd1498Szrj <http://www.gnu.org/licenses/>. */
25*38fd1498Szrj
26*38fd1498Szrj #include "tconfig.h"
27*38fd1498Szrj #include "tsystem.h"
28*38fd1498Szrj #include "coretypes.h"
29*38fd1498Szrj #include "tm.h"
30*38fd1498Szrj #include "libgcc_tm.h"
31*38fd1498Szrj #include "gthr.h"
32*38fd1498Szrj
33*38fd1498Szrj typedef unsigned int word __attribute__((mode(word)));
34*38fd1498Szrj typedef unsigned int pointer __attribute__((mode(pointer)));
35*38fd1498Szrj
36*38fd1498Szrj struct __emutls_object
37*38fd1498Szrj {
38*38fd1498Szrj word size;
39*38fd1498Szrj word align;
40*38fd1498Szrj union {
41*38fd1498Szrj pointer offset;
42*38fd1498Szrj void *ptr;
43*38fd1498Szrj } loc;
44*38fd1498Szrj void *templ;
45*38fd1498Szrj };
46*38fd1498Szrj
47*38fd1498Szrj struct __emutls_array
48*38fd1498Szrj {
49*38fd1498Szrj pointer size;
50*38fd1498Szrj void **data[];
51*38fd1498Szrj };
52*38fd1498Szrj
53*38fd1498Szrj void *__emutls_get_address (struct __emutls_object *);
54*38fd1498Szrj void __emutls_register_common (struct __emutls_object *, word, word, void *);
55*38fd1498Szrj
56*38fd1498Szrj #ifdef __GTHREADS
57*38fd1498Szrj #ifdef __GTHREAD_MUTEX_INIT
58*38fd1498Szrj static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT;
59*38fd1498Szrj #else
60*38fd1498Szrj static __gthread_mutex_t emutls_mutex;
61*38fd1498Szrj #endif
62*38fd1498Szrj static __gthread_key_t emutls_key;
63*38fd1498Szrj static pointer emutls_size;
64*38fd1498Szrj
65*38fd1498Szrj static void
emutls_destroy(void * ptr)66*38fd1498Szrj emutls_destroy (void *ptr)
67*38fd1498Szrj {
68*38fd1498Szrj struct __emutls_array *arr = ptr;
69*38fd1498Szrj pointer size = arr->size;
70*38fd1498Szrj pointer i;
71*38fd1498Szrj
72*38fd1498Szrj for (i = 0; i < size; ++i)
73*38fd1498Szrj {
74*38fd1498Szrj if (arr->data[i])
75*38fd1498Szrj free (arr->data[i][-1]);
76*38fd1498Szrj }
77*38fd1498Szrj
78*38fd1498Szrj free (ptr);
79*38fd1498Szrj }
80*38fd1498Szrj
81*38fd1498Szrj static void
emutls_init(void)82*38fd1498Szrj emutls_init (void)
83*38fd1498Szrj {
84*38fd1498Szrj #ifndef __GTHREAD_MUTEX_INIT
85*38fd1498Szrj __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex);
86*38fd1498Szrj #endif
87*38fd1498Szrj if (__gthread_key_create (&emutls_key, emutls_destroy) != 0)
88*38fd1498Szrj abort ();
89*38fd1498Szrj }
90*38fd1498Szrj #endif
91*38fd1498Szrj
92*38fd1498Szrj static void *
emutls_alloc(struct __emutls_object * obj)93*38fd1498Szrj emutls_alloc (struct __emutls_object *obj)
94*38fd1498Szrj {
95*38fd1498Szrj void *ptr;
96*38fd1498Szrj void *ret;
97*38fd1498Szrj
98*38fd1498Szrj /* We could use here posix_memalign if available and adjust
99*38fd1498Szrj emutls_destroy accordingly. */
100*38fd1498Szrj if (obj->align <= sizeof (void *))
101*38fd1498Szrj {
102*38fd1498Szrj ptr = malloc (obj->size + sizeof (void *));
103*38fd1498Szrj if (ptr == NULL)
104*38fd1498Szrj abort ();
105*38fd1498Szrj ((void **) ptr)[0] = ptr;
106*38fd1498Szrj ret = ptr + sizeof (void *);
107*38fd1498Szrj }
108*38fd1498Szrj else
109*38fd1498Szrj {
110*38fd1498Szrj ptr = malloc (obj->size + sizeof (void *) + obj->align - 1);
111*38fd1498Szrj if (ptr == NULL)
112*38fd1498Szrj abort ();
113*38fd1498Szrj ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1))
114*38fd1498Szrj & ~(pointer)(obj->align - 1));
115*38fd1498Szrj ((void **) ret)[-1] = ptr;
116*38fd1498Szrj }
117*38fd1498Szrj
118*38fd1498Szrj if (obj->templ)
119*38fd1498Szrj memcpy (ret, obj->templ, obj->size);
120*38fd1498Szrj else
121*38fd1498Szrj memset (ret, 0, obj->size);
122*38fd1498Szrj
123*38fd1498Szrj return ret;
124*38fd1498Szrj }
125*38fd1498Szrj
126*38fd1498Szrj void *
__emutls_get_address(struct __emutls_object * obj)127*38fd1498Szrj __emutls_get_address (struct __emutls_object *obj)
128*38fd1498Szrj {
129*38fd1498Szrj if (! __gthread_active_p ())
130*38fd1498Szrj {
131*38fd1498Szrj if (__builtin_expect (obj->loc.ptr == NULL, 0))
132*38fd1498Szrj obj->loc.ptr = emutls_alloc (obj);
133*38fd1498Szrj return obj->loc.ptr;
134*38fd1498Szrj }
135*38fd1498Szrj
136*38fd1498Szrj #ifndef __GTHREADS
137*38fd1498Szrj abort ();
138*38fd1498Szrj #else
139*38fd1498Szrj pointer offset = __atomic_load_n (&obj->loc.offset, __ATOMIC_ACQUIRE);
140*38fd1498Szrj
141*38fd1498Szrj if (__builtin_expect (offset == 0, 0))
142*38fd1498Szrj {
143*38fd1498Szrj static __gthread_once_t once = __GTHREAD_ONCE_INIT;
144*38fd1498Szrj __gthread_once (&once, emutls_init);
145*38fd1498Szrj __gthread_mutex_lock (&emutls_mutex);
146*38fd1498Szrj offset = obj->loc.offset;
147*38fd1498Szrj if (offset == 0)
148*38fd1498Szrj {
149*38fd1498Szrj offset = ++emutls_size;
150*38fd1498Szrj __atomic_store_n (&obj->loc.offset, offset, __ATOMIC_RELEASE);
151*38fd1498Szrj }
152*38fd1498Szrj __gthread_mutex_unlock (&emutls_mutex);
153*38fd1498Szrj }
154*38fd1498Szrj
155*38fd1498Szrj struct __emutls_array *arr = __gthread_getspecific (emutls_key);
156*38fd1498Szrj if (__builtin_expect (arr == NULL, 0))
157*38fd1498Szrj {
158*38fd1498Szrj pointer size = offset + 32;
159*38fd1498Szrj arr = calloc (size + 1, sizeof (void *));
160*38fd1498Szrj if (arr == NULL)
161*38fd1498Szrj abort ();
162*38fd1498Szrj arr->size = size;
163*38fd1498Szrj __gthread_setspecific (emutls_key, (void *) arr);
164*38fd1498Szrj }
165*38fd1498Szrj else if (__builtin_expect (offset > arr->size, 0))
166*38fd1498Szrj {
167*38fd1498Szrj pointer orig_size = arr->size;
168*38fd1498Szrj pointer size = orig_size * 2;
169*38fd1498Szrj if (offset > size)
170*38fd1498Szrj size = offset + 32;
171*38fd1498Szrj arr = realloc (arr, (size + 1) * sizeof (void *));
172*38fd1498Szrj if (arr == NULL)
173*38fd1498Szrj abort ();
174*38fd1498Szrj arr->size = size;
175*38fd1498Szrj memset (arr->data + orig_size, 0,
176*38fd1498Szrj (size - orig_size) * sizeof (void *));
177*38fd1498Szrj __gthread_setspecific (emutls_key, (void *) arr);
178*38fd1498Szrj }
179*38fd1498Szrj
180*38fd1498Szrj void *ret = arr->data[offset - 1];
181*38fd1498Szrj if (__builtin_expect (ret == NULL, 0))
182*38fd1498Szrj {
183*38fd1498Szrj ret = emutls_alloc (obj);
184*38fd1498Szrj arr->data[offset - 1] = ret;
185*38fd1498Szrj }
186*38fd1498Szrj return ret;
187*38fd1498Szrj #endif
188*38fd1498Szrj }
189*38fd1498Szrj
190*38fd1498Szrj void
__emutls_register_common(struct __emutls_object * obj,word size,word align,void * templ)191*38fd1498Szrj __emutls_register_common (struct __emutls_object *obj,
192*38fd1498Szrj word size, word align, void *templ)
193*38fd1498Szrj {
194*38fd1498Szrj if (obj->size < size)
195*38fd1498Szrj {
196*38fd1498Szrj obj->size = size;
197*38fd1498Szrj obj->templ = NULL;
198*38fd1498Szrj }
199*38fd1498Szrj if (obj->align < align)
200*38fd1498Szrj obj->align = align;
201*38fd1498Szrj if (templ && size == obj->size)
202*38fd1498Szrj obj->templ = templ;
203*38fd1498Szrj }
204