xref: /dflybsd-src/contrib/gcc-8.0/libgcc/emutls.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
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