]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/emutls.c
2008-12-09 Tobias Grosser <grosser@fim.uni-passau.de>
[thirdparty/gcc.git] / gcc / emutls.c
CommitLineData
9dda1f80 1/* TLS emulation.
2 Copyright (C) 2006 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12In addition to the permissions in the GNU General Public License, the
13Free Software Foundation gives you unlimited permission to link the
14compiled version of this file into combinations with other programs,
15and to distribute those combinations without any restriction coming
16from the use of this file. (The General Public License restrictions
17do apply in other respects; for example, they cover modification of
18the file, and distribution when not linked into a combine
19executable.)
20
21GCC is distributed in the hope that it will be useful, but WITHOUT ANY
22WARRANTY; without even the implied warranty of MERCHANTABILITY or
23FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24for more details.
25
26You should have received a copy of the GNU General Public License
27along with GCC; see the file COPYING. If not, write to the Free
28Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2902110-1301, USA. */
30
31#include "tconfig.h"
32#include "tsystem.h"
33#include "coretypes.h"
34#include "tm.h"
35#include "gthr.h"
36
37typedef unsigned int word __attribute__((mode(word)));
38typedef unsigned int pointer __attribute__((mode(pointer)));
39
40struct __emutls_object
41{
42 word size;
43 word align;
44 union {
45 pointer offset;
46 void *ptr;
47 } loc;
48 void *templ;
49};
50
bedbe58b 51struct __emutls_array
52{
53 pointer size;
54 void **data[];
55};
56
9dda1f80 57#ifdef __GTHREADS
58#ifdef __GTHREAD_MUTEX_INIT
59static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT;
60#else
61static __gthread_mutex_t emutls_mutex;
62#endif
63static __gthread_key_t emutls_key;
64static pointer emutls_size;
65
66static void
67emutls_destroy (void *ptr)
68{
bedbe58b 69 struct __emutls_array *arr = ptr;
70 pointer size = arr->size;
71 pointer i;
72
73 for (i = 0; i < size; ++i)
9dda1f80 74 {
bedbe58b 75 if (arr->data[i])
76 free (arr->data[i][-1]);
9dda1f80 77 }
bedbe58b 78
9dda1f80 79 free (ptr);
80}
81
82static void
83emutls_init (void)
84{
85#ifndef __GTHREAD_MUTEX_INIT
86 __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex);
87#endif
88 if (__gthread_key_create (&emutls_key, emutls_destroy) != 0)
89 abort ();
90}
91#endif
92
93static void *
94emutls_alloc (struct __emutls_object *obj)
95{
96 void *ptr;
97 void *ret;
98
99 /* We could use here posix_memalign if available and adjust
100 emutls_destroy accordingly. */
101 if (obj->align <= sizeof (void *))
102 {
103 ptr = malloc (obj->size + sizeof (void *));
104 if (ptr == NULL)
105 abort ();
106 ((void **) ptr)[0] = ptr;
107 ret = ptr + sizeof (void *);
108 }
109 else
110 {
111 ptr = malloc (obj->size + sizeof (void *) + obj->align - 1);
112 if (ptr == NULL)
113 abort ();
114 ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1))
115 & ~(pointer)(obj->align - 1));
116 ((void **) ret)[-1] = ptr;
117 }
118
119 if (obj->templ)
120 memcpy (ret, obj->templ, obj->size);
121 else
122 memset (ret, 0, obj->size);
123
124 return ret;
125}
126
127void *
128__emutls_get_address (struct __emutls_object *obj)
129{
130 if (! __gthread_active_p ())
131 {
132 if (__builtin_expect (obj->loc.ptr == NULL, 0))
133 obj->loc.ptr = emutls_alloc (obj);
134 return obj->loc.ptr;
135 }
136
137#ifndef __GTHREADS
138 abort ();
139#else
bedbe58b 140 pointer offset = obj->loc.offset;
9dda1f80 141
bedbe58b 142 if (__builtin_expect (offset == 0, 0))
9dda1f80 143 {
144 static __gthread_once_t once = __GTHREAD_ONCE_INIT;
145 __gthread_once (&once, emutls_init);
146 __gthread_mutex_lock (&emutls_mutex);
147 offset = ++emutls_size;
148 obj->loc.offset = offset;
149 __gthread_mutex_unlock (&emutls_mutex);
150 }
9dda1f80 151
bedbe58b 152 struct __emutls_array *arr = __gthread_getspecific (emutls_key);
9dda1f80 153 if (__builtin_expect (arr == NULL, 0))
154 {
155 pointer size = offset + 32;
156 arr = calloc (size, sizeof (void *));
157 if (arr == NULL)
158 abort ();
bedbe58b 159 arr->size = size;
9dda1f80 160 __gthread_setspecific (emutls_key, (void *) arr);
161 }
bedbe58b 162 else if (__builtin_expect (offset >= arr->size, 0))
9dda1f80 163 {
bedbe58b 164 pointer orig_size = arr->size;
9dda1f80 165 pointer size = orig_size * 2;
166 if (offset >= size)
167 size = offset + 32;
168 arr = realloc (arr, size * sizeof (void *));
169 if (arr == NULL)
170 abort ();
bedbe58b 171 arr->size = size;
172 memset (arr->data + orig_size - 1, 0,
173 (size - orig_size) * sizeof (void *));
9dda1f80 174 __gthread_setspecific (emutls_key, (void *) arr);
175 }
176
bedbe58b 177 void *ret = arr->data[offset - 1];
9dda1f80 178 if (__builtin_expect (ret == NULL, 0))
179 {
180 ret = emutls_alloc (obj);
bedbe58b 181 arr->data[offset - 1] = ret;
9dda1f80 182 }
183 return ret;
184#endif
185}
186
187void
188__emutls_register_common (struct __emutls_object *obj,
189 word size, word align, void *templ)
190{
191 if (obj->size < size)
192 {
193 obj->size = size;
194 obj->templ = NULL;
195 }
196 if (obj->align < align)
197 obj->align = align;
198 if (templ && size == obj->size)
199 obj->templ = templ;
200}