2007-03-01 Paul Brook <paul@codesourcery.com>
[official-gcc.git] / gcc / emutls.c
blobf26d21772e3907607352891f604ca8b6fe13dfc7
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 #ifdef __GTHREADS
52 #ifdef __GTHREAD_MUTEX_INIT
53 static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT;
54 #else
55 static __gthread_mutex_t emutls_mutex;
56 #endif
57 static __gthread_key_t emutls_key;
58 static pointer emutls_size;
60 static void
61 emutls_destroy (void *ptr)
63 void ***arr = (void ***) ptr;
64 unsigned long int size = (unsigned long int) arr[0];
65 ++arr;
66 while (--size)
68 if (*arr)
69 free ((*arr)[-1]);
70 ++arr;
72 free (ptr);
75 static void
76 emutls_init (void)
78 #ifndef __GTHREAD_MUTEX_INIT
79 __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex);
80 #endif
81 if (__gthread_key_create (&emutls_key, emutls_destroy) != 0)
82 abort ();
84 #endif
86 static void *
87 emutls_alloc (struct __emutls_object *obj)
89 void *ptr;
90 void *ret;
92 /* We could use here posix_memalign if available and adjust
93 emutls_destroy accordingly. */
94 if (obj->align <= sizeof (void *))
96 ptr = malloc (obj->size + sizeof (void *));
97 if (ptr == NULL)
98 abort ();
99 ((void **) ptr)[0] = ptr;
100 ret = ptr + sizeof (void *);
102 else
104 ptr = malloc (obj->size + sizeof (void *) + obj->align - 1);
105 if (ptr == NULL)
106 abort ();
107 ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1))
108 & ~(pointer)(obj->align - 1));
109 ((void **) ret)[-1] = ptr;
112 if (obj->templ)
113 memcpy (ret, obj->templ, obj->size);
114 else
115 memset (ret, 0, obj->size);
117 return ret;
120 void *
121 __emutls_get_address (struct __emutls_object *obj)
123 if (! __gthread_active_p ())
125 if (__builtin_expect (obj->loc.ptr == NULL, 0))
126 obj->loc.ptr = emutls_alloc (obj);
127 return obj->loc.ptr;
130 #ifndef __GTHREADS
131 abort ();
132 #else
133 pointer offset;
135 if (__builtin_expect (obj->loc.offset == 0, 0))
137 static __gthread_once_t once = __GTHREAD_ONCE_INIT;
138 __gthread_once (&once, emutls_init);
139 __gthread_mutex_lock (&emutls_mutex);
140 offset = ++emutls_size;
141 obj->loc.offset = offset;
142 __gthread_mutex_unlock (&emutls_mutex);
144 else
145 offset = obj->loc.offset;
147 void **arr = (void **) __gthread_getspecific (emutls_key);
148 if (__builtin_expect (arr == NULL, 0))
150 pointer size = offset + 32;
151 arr = calloc (size, sizeof (void *));
152 if (arr == NULL)
153 abort ();
154 arr[0] = (void *) size;
155 __gthread_setspecific (emutls_key, (void *) arr);
157 else if (__builtin_expect (offset >= (pointer) arr[0], 0))
159 pointer orig_size = (pointer) arr[0];
160 pointer size = orig_size * 2;
161 if (offset >= size)
162 size = offset + 32;
163 arr = realloc (arr, size * sizeof (void *));
164 if (arr == NULL)
165 abort ();
166 memset (arr + orig_size, 0, (size - orig_size) * sizeof (void *));
167 __gthread_setspecific (emutls_key, (void *) arr);
170 void *ret = arr[offset];
171 if (__builtin_expect (ret == NULL, 0))
173 ret = emutls_alloc (obj);
174 arr[offset] = ret;
176 return ret;
177 #endif
180 void
181 __emutls_register_common (struct __emutls_object *obj,
182 word size, word align, void *templ)
184 if (obj->size < size)
186 obj->size = size;
187 obj->templ = NULL;
189 if (obj->align < align)
190 obj->align = align;
191 if (templ && size == obj->size)
192 obj->templ = templ;