OSDN Git Service

Add dbg count support for ccp
[pf3gnuchains/gcc-fork.git] / gcc / emutls.c
1 /* TLS emulation.
2    Copyright (C) 2006, 2008 Free Software Foundation, Inc.
3    Contributed by Jakub Jelinek <jakub@redhat.com>.
4
5 This file is part of GCC.
6
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.
11
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.)
20
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.
25
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.  */
30
31 #include "tconfig.h"
32 #include "tsystem.h"
33 #include "coretypes.h"
34 #include "tm.h"
35 #include "gthr.h"
36
37 typedef unsigned int word __attribute__((mode(word)));
38 typedef unsigned int pointer __attribute__((mode(pointer)));
39
40 struct __emutls_object
41 {
42   word size;
43   word align;
44   union {
45     pointer offset;
46     void *ptr;
47   } loc;
48   void *templ;
49 };
50
51 struct __emutls_array
52 {
53   pointer size;
54   void **data[];
55 };
56
57 void *__emutls_get_address (struct __emutls_object *);
58 void __emutls_register_common (struct __emutls_object *, word, word, void *);
59
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;
68
69 static void
70 emutls_destroy (void *ptr)
71 {
72   struct __emutls_array *arr = ptr;
73   pointer size = arr->size;
74   pointer i;
75
76   for (i = 0; i < size; ++i)
77     {
78       if (arr->data[i])
79         free (arr->data[i][-1]);
80     }
81
82   free (ptr);
83 }
84
85 static void
86 emutls_init (void)
87 {
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 ();
93 }
94 #endif
95
96 static void *
97 emutls_alloc (struct __emutls_object *obj)
98 {
99   void *ptr;
100   void *ret;
101
102   /* We could use here posix_memalign if available and adjust
103      emutls_destroy accordingly.  */
104   if (obj->align <= sizeof (void *))
105     {
106       ptr = malloc (obj->size + sizeof (void *));
107       if (ptr == NULL)
108         abort ();
109       ((void **) ptr)[0] = ptr;
110       ret = ptr + sizeof (void *);
111     }
112   else
113     {
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;
120     }
121
122   if (obj->templ)
123     memcpy (ret, obj->templ, obj->size);
124   else
125     memset (ret, 0, obj->size);
126
127   return ret;
128 }
129
130 void *
131 __emutls_get_address (struct __emutls_object *obj)
132 {
133   if (! __gthread_active_p ())
134     {
135       if (__builtin_expect (obj->loc.ptr == NULL, 0))
136         obj->loc.ptr = emutls_alloc (obj);
137       return obj->loc.ptr;
138     }
139
140 #ifndef __GTHREADS
141   abort ();
142 #else
143   pointer offset = obj->loc.offset;
144
145   if (__builtin_expect (offset == 0, 0))
146     {
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)
152         {
153           offset = ++emutls_size;
154           obj->loc.offset = offset;
155         }
156       __gthread_mutex_unlock (&emutls_mutex);
157     }
158
159   struct __emutls_array *arr = __gthread_getspecific (emutls_key);
160   if (__builtin_expect (arr == NULL, 0))
161     {
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);
168     }
169   else if (__builtin_expect (offset >= arr->size, 0))
170     {
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);
182     }
183
184   void *ret = arr->data[offset - 1];
185   if (__builtin_expect (ret == NULL, 0))
186     {
187       ret = emutls_alloc (obj);
188       arr->data[offset - 1] = ret;
189     }
190   return ret;
191 #endif
192 }
193
194 void
195 __emutls_register_common (struct __emutls_object *obj,
196                           word size, word align, void *templ)
197 {
198   if (obj->size < size)
199     {
200       obj->size = size;
201       obj->templ = NULL;
202     }
203   if (obj->align < align)
204     obj->align = align;
205   if (templ && size == obj->size)
206     obj->templ = templ;
207 }