2009-01-28 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / emutls.c
blob32e14a1c97e232a8807d5bd4350dc27a758fe2cb
1 /* TLS emulation.
2 Copyright (C) 2006 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 2, or (at your option) any later
10 version.
12 In addition to the permissions in the GNU General Public License, the
13 Free Software Foundation gives you unlimited permission to link the
14 compiled version of this file into combinations with other programs,
15 and to distribute those combinations without any restriction coming
16 from the use of this file. (The General Public License restrictions
17 do apply in other respects; for example, they cover modification of
18 the file, and distribution when not linked into a combine
19 executable.)
21 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
22 WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 for more details.
26 You should have received a copy of the GNU General Public License
27 along with GCC; see the file COPYING. If not, write to the Free
28 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
29 02110-1301, USA. */
31 #include "tconfig.h"
32 #include "tsystem.h"
33 #include "coretypes.h"
34 #include "tm.h"
35 #include "gthr.h"
37 typedef unsigned int word __attribute__((mode(word)));
38 typedef unsigned int pointer __attribute__((mode(pointer)));
40 struct __emutls_object
42 word size;
43 word align;
44 union {
45 pointer offset;
46 void *ptr;
47 } loc;
48 void *templ;
51 struct __emutls_array
53 pointer size;
54 void **data[];
57 void *__emutls_get_address (struct __emutls_object *);
58 void __emutls_register_common (struct __emutls_object *, word, word, void *);
60 #ifdef __GTHREADS
61 #ifdef __GTHREAD_MUTEX_INIT
62 static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT;
63 #else
64 static __gthread_mutex_t emutls_mutex;
65 #endif
66 static __gthread_key_t emutls_key;
67 static pointer emutls_size;
69 static void
70 emutls_destroy (void *ptr)
72 struct __emutls_array *arr = ptr;
73 pointer size = arr->size;
74 pointer i;
76 for (i = 0; i < size; ++i)
78 if (arr->data[i])
79 free (arr->data[i][-1]);
82 free (ptr);
85 static void
86 emutls_init (void)
88 #ifndef __GTHREAD_MUTEX_INIT
89 __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex);
90 #endif
91 if (__gthread_key_create (&emutls_key, emutls_destroy) != 0)
92 abort ();
94 #endif
96 static void *
97 emutls_alloc (struct __emutls_object *obj)
99 void *ptr;
100 void *ret;
102 /* We could use here posix_memalign if available and adjust
103 emutls_destroy accordingly. */
104 if (obj->align <= sizeof (void *))
106 ptr = malloc (obj->size + sizeof (void *));
107 if (ptr == NULL)
108 abort ();
109 ((void **) ptr)[0] = ptr;
110 ret = ptr + sizeof (void *);
112 else
114 ptr = malloc (obj->size + sizeof (void *) + obj->align - 1);
115 if (ptr == NULL)
116 abort ();
117 ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1))
118 & ~(pointer)(obj->align - 1));
119 ((void **) ret)[-1] = ptr;
122 if (obj->templ)
123 memcpy (ret, obj->templ, obj->size);
124 else
125 memset (ret, 0, obj->size);
127 return ret;
130 void *
131 __emutls_get_address (struct __emutls_object *obj)
133 if (! __gthread_active_p ())
135 if (__builtin_expect (obj->loc.ptr == NULL, 0))
136 obj->loc.ptr = emutls_alloc (obj);
137 return obj->loc.ptr;
140 #ifndef __GTHREADS
141 abort ();
142 #else
143 pointer offset = obj->loc.offset;
145 if (__builtin_expect (offset == 0, 0))
147 static __gthread_once_t once = __GTHREAD_ONCE_INIT;
148 __gthread_once (&once, emutls_init);
149 __gthread_mutex_lock (&emutls_mutex);
150 offset = obj->loc.offset;
151 if (offset == 0)
153 offset = ++emutls_size;
154 obj->loc.offset = offset;
156 __gthread_mutex_unlock (&emutls_mutex);
159 struct __emutls_array *arr = __gthread_getspecific (emutls_key);
160 if (__builtin_expect (arr == NULL, 0))
162 pointer size = offset + 32;
163 arr = calloc (size, sizeof (void *));
164 if (arr == NULL)
165 abort ();
166 arr->size = size;
167 __gthread_setspecific (emutls_key, (void *) arr);
169 else if (__builtin_expect (offset >= arr->size, 0))
171 pointer orig_size = arr->size;
172 pointer size = orig_size * 2;
173 if (offset >= size)
174 size = offset + 32;
175 arr = realloc (arr, size * sizeof (void *));
176 if (arr == NULL)
177 abort ();
178 arr->size = size;
179 memset (arr->data + orig_size - 1, 0,
180 (size - orig_size) * sizeof (void *));
181 __gthread_setspecific (emutls_key, (void *) arr);
184 void *ret = arr->data[offset - 1];
185 if (__builtin_expect (ret == NULL, 0))
187 ret = emutls_alloc (obj);
188 arr->data[offset - 1] = ret;
190 return ret;
191 #endif
194 void
195 __emutls_register_common (struct __emutls_object *obj,
196 word size, word align, void *templ)
198 if (obj->size < size)
200 obj->size = size;
201 obj->templ = NULL;
203 if (obj->align < align)
204 obj->align = align;
205 if (templ && size == obj->size)
206 obj->templ = templ;