2 Copyright (C) 2006-2023 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
28 #include "coretypes.h"
30 #include "libgcc_tm.h"
33 typedef unsigned int word
__attribute__((mode(word
)));
34 typedef unsigned int pointer
__attribute__((mode(pointer
)));
36 struct __emutls_object
53 /* EMUTLS_ATTR is provided to allow targets to build the emulated tls
54 routines as weak definitions, for example.
55 If there is no definition, fall back to the default. */
61 void *__emutls_get_address (struct __emutls_object
*);
63 void __emutls_register_common (struct __emutls_object
*, word
, word
, void *);
66 #ifdef __GTHREAD_MUTEX_INIT
67 static __gthread_mutex_t emutls_mutex
= __GTHREAD_MUTEX_INIT
;
69 static __gthread_mutex_t emutls_mutex
;
71 static __gthread_key_t emutls_key
;
72 static pointer emutls_size
;
75 emutls_destroy (void *ptr
)
77 struct __emutls_array
*arr
= ptr
;
78 pointer size
= arr
->size
;
81 for (i
= 0; i
< size
; ++i
)
84 free (arr
->data
[i
][-1]);
93 #ifndef __GTHREAD_MUTEX_INIT
94 __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex
);
96 if (__gthread_key_create (&emutls_key
, emutls_destroy
) != 0)
102 emutls_alloc (struct __emutls_object
*obj
)
107 /* We could use here posix_memalign if available and adjust
108 emutls_destroy accordingly. */
109 if (obj
->align
<= sizeof (void *))
111 ptr
= malloc (obj
->size
+ sizeof (void *));
114 ((void **) ptr
)[0] = ptr
;
115 ret
= ptr
+ sizeof (void *);
119 ptr
= malloc (obj
->size
+ sizeof (void *) + obj
->align
- 1);
122 ret
= (void *) (((pointer
) (ptr
+ sizeof (void *) + obj
->align
- 1))
123 & ~(pointer
)(obj
->align
- 1));
124 ((void **) ret
)[-1] = ptr
;
128 memcpy (ret
, obj
->templ
, obj
->size
);
130 memset (ret
, 0, obj
->size
);
135 /* Despite applying the attribute to the declaration, in this case the mis-
136 match between the builtin's declaration [void * (*)(void *)] and the
137 implementation here, causes the decl. attributes to be discarded. */
140 __emutls_get_address (struct __emutls_object
*obj
)
142 if (! __gthread_active_p ())
144 if (__builtin_expect (obj
->loc
.ptr
== NULL
, 0))
145 obj
->loc
.ptr
= emutls_alloc (obj
);
152 pointer offset
= __atomic_load_n (&obj
->loc
.offset
, __ATOMIC_ACQUIRE
);
154 if (__builtin_expect (offset
== 0, 0))
156 static __gthread_once_t once
= __GTHREAD_ONCE_INIT
;
157 __gthread_once (&once
, emutls_init
);
158 __gthread_mutex_lock (&emutls_mutex
);
159 offset
= obj
->loc
.offset
;
162 offset
= ++emutls_size
;
163 __atomic_store_n (&obj
->loc
.offset
, offset
, __ATOMIC_RELEASE
);
165 __gthread_mutex_unlock (&emutls_mutex
);
168 struct __emutls_array
*arr
= __gthread_getspecific (emutls_key
);
169 if (__builtin_expect (arr
== NULL
, 0))
171 pointer size
= offset
+ 32;
172 arr
= calloc (size
+ 1, sizeof (void *));
176 __gthread_setspecific (emutls_key
, (void *) arr
);
178 else if (__builtin_expect (offset
> arr
->size
, 0))
180 pointer orig_size
= arr
->size
;
181 pointer size
= orig_size
* 2;
184 arr
= realloc (arr
, (size
+ 1) * sizeof (void *));
188 memset (arr
->data
+ orig_size
, 0,
189 (size
- orig_size
) * sizeof (void *));
190 __gthread_setspecific (emutls_key
, (void *) arr
);
193 void *ret
= arr
->data
[offset
- 1];
194 if (__builtin_expect (ret
== NULL
, 0))
196 ret
= emutls_alloc (obj
);
197 arr
->data
[offset
- 1] = ret
;
204 __emutls_register_common (struct __emutls_object
*obj
,
205 word size
, word align
, void *templ
)
207 if (obj
->size
< size
)
212 if (obj
->align
< align
)
214 if (templ
&& size
== obj
->size
)