2 Copyright (C) 2006-2024 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. */
60 /* __emutls_get_address and __emutls_register_common are registered as
61 builtins, but the compiler struct __emutls_object doesn't have
62 a union in there and is only created when actually needed for
63 the calls to the builtins, so the builtins are created with void *
64 arguments rather than struct __emutls_object *. Avoid
65 -Wbuiltin-declaration-mismatch warnings. */
66 #pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch"
69 void *__emutls_get_address (struct __emutls_object
*);
71 void __emutls_register_common (struct __emutls_object
*, word
, word
, void *);
74 #ifdef __GTHREAD_MUTEX_INIT
75 static __gthread_mutex_t emutls_mutex
= __GTHREAD_MUTEX_INIT
;
77 static __gthread_mutex_t emutls_mutex
;
79 static __gthread_key_t emutls_key
;
80 static pointer emutls_size
;
83 emutls_destroy (void *ptr
)
85 struct __emutls_array
*arr
= ptr
;
86 pointer size
= arr
->size
;
89 for (i
= 0; i
< size
; ++i
)
92 free (arr
->data
[i
][-1]);
101 #ifndef __GTHREAD_MUTEX_INIT
102 __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex
);
104 if (__gthread_key_create (&emutls_key
, emutls_destroy
) != 0)
110 emutls_alloc (struct __emutls_object
*obj
)
115 /* We could use here posix_memalign if available and adjust
116 emutls_destroy accordingly. */
117 if (obj
->align
<= sizeof (void *))
119 ptr
= malloc (obj
->size
+ sizeof (void *));
122 ((void **) ptr
)[0] = ptr
;
123 ret
= ptr
+ sizeof (void *);
127 ptr
= malloc (obj
->size
+ sizeof (void *) + obj
->align
- 1);
130 ret
= (void *) (((pointer
) (ptr
+ sizeof (void *) + obj
->align
- 1))
131 & ~(pointer
)(obj
->align
- 1));
132 ((void **) ret
)[-1] = ptr
;
136 memcpy (ret
, obj
->templ
, obj
->size
);
138 memset (ret
, 0, obj
->size
);
143 /* Despite applying the attribute to the declaration, in this case the mis-
144 match between the builtin's declaration [void * (*)(void *)] and the
145 implementation here, causes the decl. attributes to be discarded. */
148 __emutls_get_address (struct __emutls_object
*obj
)
150 if (! __gthread_active_p ())
152 if (__builtin_expect (obj
->loc
.ptr
== NULL
, 0))
153 obj
->loc
.ptr
= emutls_alloc (obj
);
160 pointer offset
= __atomic_load_n (&obj
->loc
.offset
, __ATOMIC_ACQUIRE
);
162 if (__builtin_expect (offset
== 0, 0))
164 static __gthread_once_t once
= __GTHREAD_ONCE_INIT
;
165 __gthread_once (&once
, emutls_init
);
166 __gthread_mutex_lock (&emutls_mutex
);
167 offset
= obj
->loc
.offset
;
170 offset
= ++emutls_size
;
171 __atomic_store_n (&obj
->loc
.offset
, offset
, __ATOMIC_RELEASE
);
173 __gthread_mutex_unlock (&emutls_mutex
);
176 struct __emutls_array
*arr
= __gthread_getspecific (emutls_key
);
177 if (__builtin_expect (arr
== NULL
, 0))
179 pointer size
= offset
+ 32;
180 arr
= calloc (size
+ 1, sizeof (void *));
184 __gthread_setspecific (emutls_key
, (void *) arr
);
186 else if (__builtin_expect (offset
> arr
->size
, 0))
188 pointer orig_size
= arr
->size
;
189 pointer size
= orig_size
* 2;
192 arr
= realloc (arr
, (size
+ 1) * sizeof (void *));
196 memset (arr
->data
+ orig_size
, 0,
197 (size
- orig_size
) * sizeof (void *));
198 __gthread_setspecific (emutls_key
, (void *) arr
);
201 void *ret
= arr
->data
[offset
- 1];
202 if (__builtin_expect (ret
== NULL
, 0))
204 ret
= emutls_alloc (obj
);
205 arr
->data
[offset
- 1] = ret
;
212 __emutls_register_common (struct __emutls_object
*obj
,
213 word size
, word align
, void *templ
)
215 if (obj
->size
< size
)
220 if (obj
->align
< align
)
222 if (templ
&& size
== obj
->size
)