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