Mercurial > hg > CbC > CbC_gcc
annotate gcc/config/vxlib-tls.c @ 55:77e2b8dfacca gcc-4.4.5
update it from 4.4.3 to 4.5.0
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 12 Feb 2010 23:39:51 +0900 |
parents | a06113de4d67 |
children |
rev | line source |
---|---|
0 | 1 /* Copyright (C) 2002, 2003, 2004, 2005, 2009 Free Software Foundation, Inc. |
2 Contributed by Zack Weinberg <zack@codesourcery.com> | |
3 | |
4 This file is part of GCC. | |
5 | |
6 GCC is free software; you can redistribute it and/or modify it under | |
7 the terms of the GNU General Public License as published by the Free | |
8 Software Foundation; either version 3, or (at your option) any later | |
9 version. | |
10 | |
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 Under Section 7 of GPL version 3, you are granted additional | |
17 permissions described in the GCC Runtime Library Exception, version | |
18 3.1, as published by the Free Software Foundation. | |
19 | |
20 You should have received a copy of the GNU General Public License and | |
21 a copy of the GCC Runtime Library Exception along with this program; | |
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 <http://www.gnu.org/licenses/>. */ | |
24 | |
25 /* Threads compatibility routines for libgcc2 for VxWorks. | |
26 These are out-of-line routines called from gthr-vxworks.h. | |
27 | |
28 This file provides the TLS related support routines, calling specific | |
29 VxWorks kernel entry points for this purpose. The base VxWorks 5.x kernels | |
30 don't feature these entry points, and we provide gthr_supp_vxw_5x.c as an | |
31 option to fill this gap. Asking users to rebuild a kernel is not to be | |
32 taken lightly, still, so we have isolated these routines from the rest of | |
33 vxlib to ensure that the kernel dependencies are only dragged when really | |
34 necessary. */ | |
35 | |
36 #include "tconfig.h" | |
37 #include "tsystem.h" | |
38 #include "gthr.h" | |
39 | |
40 #if defined(__GTHREADS) | |
41 #include <vxWorks.h> | |
42 #ifndef __RTP__ | |
43 #include <vxLib.h> | |
44 #endif | |
45 #include <taskLib.h> | |
46 #ifndef __RTP__ | |
47 #include <taskHookLib.h> | |
48 #else | |
49 # include <errno.h> | |
50 #endif | |
51 | |
52 /* Thread-local storage. | |
53 | |
54 We reserve a field in the TCB to point to a dynamically allocated | |
55 array which is used to store TLS values. A TLS key is simply an | |
56 offset in this array. The exact location of the TCB field is not | |
57 known to this code nor to vxlib.c -- all access to it indirects | |
58 through the routines __gthread_get_tls_data and | |
59 __gthread_set_tls_data, which are provided by the VxWorks kernel. | |
60 | |
61 There is also a global array which records which keys are valid and | |
62 which have destructors. | |
63 | |
64 A task delete hook is installed to execute key destructors. The | |
65 routines __gthread_enter_tls_dtor_context and | |
66 __gthread_leave_tls_dtor_context, which are also provided by the | |
67 kernel, ensure that it is safe to call free() on memory allocated | |
68 by the task being deleted. (This is a no-op on VxWorks 5, but | |
69 a major undertaking on AE.) | |
70 | |
71 The task delete hook is only installed when at least one thread | |
72 has TLS data. This is a necessary precaution, to allow this module | |
73 to be unloaded - a module with a hook can not be removed. | |
74 | |
75 Since this interface is used to allocate only a small number of | |
76 keys, the table size is small and static, which simplifies the | |
77 code quite a bit. Revisit this if and when it becomes necessary. */ | |
78 | |
79 #define MAX_KEYS 4 | |
80 | |
81 /* This is the structure pointed to by the pointer returned | |
82 by __gthread_get_tls_data. */ | |
83 struct tls_data | |
84 { | |
85 int *owner; | |
86 void *values[MAX_KEYS]; | |
87 unsigned int generation[MAX_KEYS]; | |
88 }; | |
89 | |
90 /* To make sure we only delete TLS data associated with this object, | |
91 include a pointer to a local variable in the TLS data object. */ | |
92 static int self_owner; | |
93 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
94 /* Flag to check whether the delete hook is installed. Once installed |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
95 it is only removed when unloading this module. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
96 static volatile int delete_hook_installed; |
0 | 97 |
98 /* kernel provided routines */ | |
99 extern void *__gthread_get_tls_data (void); | |
100 extern void __gthread_set_tls_data (void *data); | |
101 | |
102 extern void __gthread_enter_tls_dtor_context (void); | |
103 extern void __gthread_leave_tls_dtor_context (void); | |
104 | |
105 | |
106 /* This is a global structure which records all of the active keys. | |
107 | |
108 A key is potentially valid (i.e. has been handed out by | |
109 __gthread_key_create) iff its generation count in this structure is | |
110 even. In that case, the matching entry in the dtors array is a | |
111 routine to be called when a thread terminates with a valid, | |
112 non-NULL specific value for that key. | |
113 | |
114 A key is actually valid in a thread T iff the generation count | |
115 stored in this structure is equal to the generation count stored in | |
116 T's specific-value structure. */ | |
117 | |
118 typedef void (*tls_dtor) (void *); | |
119 | |
120 struct tls_keys | |
121 { | |
122 tls_dtor dtor[MAX_KEYS]; | |
123 unsigned int generation[MAX_KEYS]; | |
124 }; | |
125 | |
126 #define KEY_VALID_P(key) !(tls_keys.generation[key] & 1) | |
127 | |
128 /* Note: if MAX_KEYS is increased, this initializer must be updated | |
129 to match. All the generation counts begin at 1, which means no | |
130 key is valid. */ | |
131 static struct tls_keys tls_keys = | |
132 { | |
133 { 0, 0, 0, 0 }, | |
134 { 1, 1, 1, 1 } | |
135 }; | |
136 | |
137 /* This lock protects the tls_keys structure. */ | |
138 static __gthread_mutex_t tls_lock; | |
139 | |
140 static __gthread_once_t tls_init_guard = __GTHREAD_ONCE_INIT; | |
141 | |
142 /* Internal routines. */ | |
143 | |
144 /* The task TCB has just been deleted. Call the destructor | |
145 function for each TLS key that has both a destructor and | |
146 a non-NULL specific value in this thread. | |
147 | |
148 This routine does not need to take tls_lock; the generation | |
149 count protects us from calling a stale destructor. It does | |
150 need to read tls_keys.dtor[key] atomically. */ | |
151 | |
152 static void | |
153 tls_delete_hook (void *tcb ATTRIBUTE_UNUSED) | |
154 { | |
155 struct tls_data *data; | |
156 __gthread_key_t key; | |
157 | |
158 #ifdef __RTP__ | |
159 data = __gthread_get_tls_data (); | |
160 #else | |
161 /* In kernel mode, we can be called in the context of the thread | |
162 doing the killing, so must use the TCB to determine the data of | |
163 the thread being killed. */ | |
164 data = __gthread_get_tsd_data (tcb); | |
165 #endif | |
166 | |
167 if (data && data->owner == &self_owner) | |
168 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
169 #ifdef __RTP__ |
0 | 170 __gthread_enter_tls_dtor_context (); |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
171 #else |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
172 __gthread_enter_tsd_dtor_context (tcb); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
173 #endif |
0 | 174 for (key = 0; key < MAX_KEYS; key++) |
175 { | |
176 if (data->generation[key] == tls_keys.generation[key]) | |
177 { | |
178 tls_dtor dtor = tls_keys.dtor[key]; | |
179 | |
180 if (dtor) | |
181 dtor (data->values[key]); | |
182 } | |
183 } | |
184 free (data); | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
185 #ifdef __RTP__ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
186 __gthread_leave_tls_dtor_context (); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
187 #else |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
188 __gthread_leave_tsd_dtor_context (); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
189 #endif |
0 | 190 |
191 #ifdef __RTP__ | |
192 __gthread_set_tls_data (0); | |
193 #else | |
194 __gthread_set_tsd_data (tcb, 0); | |
195 #endif | |
196 } | |
197 } | |
198 | |
199 /* Initialize global data used by the TLS system. */ | |
200 static void | |
201 tls_init (void) | |
202 { | |
203 __GTHREAD_MUTEX_INIT_FUNCTION (&tls_lock); | |
204 } | |
205 | |
206 static void tls_destructor (void) __attribute__ ((destructor)); | |
207 static void | |
208 tls_destructor (void) | |
209 { | |
210 #ifdef __RTP__ | |
211 /* All threads but this one should have exited by now. */ | |
212 tls_delete_hook (NULL); | |
213 #endif | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
214 /* Unregister the hook. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
215 if (delete_hook_installed) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
216 taskDeleteHookDelete ((FUNCPTR)tls_delete_hook); |
0 | 217 |
218 if (tls_init_guard.done && __gthread_mutex_lock (&tls_lock) != ERROR) | |
219 semDelete (tls_lock); | |
220 } | |
221 | |
222 /* External interface */ | |
223 | |
224 /* Store in KEYP a value which can be passed to __gthread_setspecific/ | |
225 __gthread_getspecific to store and retrieve a value which is | |
226 specific to each calling thread. If DTOR is not NULL, it will be | |
227 called when a thread terminates with a non-NULL specific value for | |
228 this key, with the value as its sole argument. */ | |
229 | |
230 int | |
231 __gthread_key_create (__gthread_key_t *keyp, tls_dtor dtor) | |
232 { | |
233 __gthread_key_t key; | |
234 | |
235 __gthread_once (&tls_init_guard, tls_init); | |
236 | |
237 if (__gthread_mutex_lock (&tls_lock) == ERROR) | |
238 return errno; | |
239 | |
240 for (key = 0; key < MAX_KEYS; key++) | |
241 if (!KEY_VALID_P (key)) | |
242 goto found_slot; | |
243 | |
244 /* no room */ | |
245 __gthread_mutex_unlock (&tls_lock); | |
246 return EAGAIN; | |
247 | |
248 found_slot: | |
249 tls_keys.generation[key]++; /* making it even */ | |
250 tls_keys.dtor[key] = dtor; | |
251 *keyp = key; | |
252 __gthread_mutex_unlock (&tls_lock); | |
253 return 0; | |
254 } | |
255 | |
256 /* Invalidate KEY; it can no longer be used as an argument to | |
257 setspecific/getspecific. Note that this does NOT call destructor | |
258 functions for any live values for this key. */ | |
259 int | |
260 __gthread_key_delete (__gthread_key_t key) | |
261 { | |
262 if (key >= MAX_KEYS) | |
263 return EINVAL; | |
264 | |
265 __gthread_once (&tls_init_guard, tls_init); | |
266 | |
267 if (__gthread_mutex_lock (&tls_lock) == ERROR) | |
268 return errno; | |
269 | |
270 if (!KEY_VALID_P (key)) | |
271 { | |
272 __gthread_mutex_unlock (&tls_lock); | |
273 return EINVAL; | |
274 } | |
275 | |
276 tls_keys.generation[key]++; /* making it odd */ | |
277 tls_keys.dtor[key] = 0; | |
278 | |
279 __gthread_mutex_unlock (&tls_lock); | |
280 return 0; | |
281 } | |
282 | |
283 /* Retrieve the thread-specific value for KEY. If it has never been | |
284 set in this thread, or KEY is invalid, returns NULL. | |
285 | |
286 It does not matter if this function races with key_create or | |
287 key_delete; the worst that can happen is you get a value other than | |
288 the one that a serialized implementation would have provided. */ | |
289 | |
290 void * | |
291 __gthread_getspecific (__gthread_key_t key) | |
292 { | |
293 struct tls_data *data; | |
294 | |
295 if (key >= MAX_KEYS) | |
296 return 0; | |
297 | |
298 data = __gthread_get_tls_data (); | |
299 | |
300 if (!data) | |
301 return 0; | |
302 | |
303 if (data->generation[key] != tls_keys.generation[key]) | |
304 return 0; | |
305 | |
306 return data->values[key]; | |
307 } | |
308 | |
309 /* Set the thread-specific value for KEY. If KEY is invalid, or | |
310 memory allocation fails, returns -1, otherwise 0. | |
311 | |
312 The generation count protects this function against races with | |
313 key_create/key_delete; the worst thing that can happen is that a | |
314 value is successfully stored into a dead generation (and then | |
315 immediately becomes invalid). However, we do have to make sure | |
316 to read tls_keys.generation[key] atomically. */ | |
317 | |
318 int | |
319 __gthread_setspecific (__gthread_key_t key, void *value) | |
320 { | |
321 struct tls_data *data; | |
322 unsigned int generation; | |
323 | |
324 if (key >= MAX_KEYS) | |
325 return EINVAL; | |
326 | |
327 data = __gthread_get_tls_data (); | |
328 if (!data) | |
329 { | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
330 if (!delete_hook_installed) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
331 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
332 /* Install the delete hook. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
333 if (__gthread_mutex_lock (&tls_lock) == ERROR) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
334 return ENOMEM; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
335 if (!delete_hook_installed) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
336 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
337 taskDeleteHookAdd ((FUNCPTR)tls_delete_hook); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
338 delete_hook_installed = 1; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
339 } |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
340 __gthread_mutex_unlock (&tls_lock); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
341 } |
0 | 342 |
343 data = malloc (sizeof (struct tls_data)); | |
344 if (!data) | |
345 return ENOMEM; | |
346 | |
347 memset (data, 0, sizeof (struct tls_data)); | |
348 data->owner = &self_owner; | |
349 __gthread_set_tls_data (data); | |
350 } | |
351 | |
352 generation = tls_keys.generation[key]; | |
353 | |
354 if (generation & 1) | |
355 return EINVAL; | |
356 | |
357 data->generation[key] = generation; | |
358 data->values[key] = value; | |
359 | |
360 return 0; | |
361 } | |
362 #endif /* __GTHREADS */ |