* arm.c (emit_set_insn): New function.
[official-gcc.git] / gcc / config / vxlib.c
blob8625981a3151fc3c261ce5df6a2ee4ff48095365
1 /* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
2 Contributed by Zack Weinberg <zack@codesourcery.com>
4 This file is part of GCC.
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 2, or (at your option) any later
9 version.
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.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA. */
21 /* As a special exception, if you link this library with other files,
22 some of which are compiled with GCC, to produce an executable,
23 this library does not by itself cause the resulting executable
24 to be covered by the GNU General Public License.
25 This exception does not however invalidate any other reasons why
26 the executable file might be covered by the GNU General Public License. */
28 /* Threads compatibility routines for libgcc2 for VxWorks.
29 These are out-of-line routines called from gthr-vxworks.h. */
31 #include "tconfig.h"
32 #include "tsystem.h"
33 #include "gthr.h"
35 #if defined(__GTHREADS)
36 #include <vxWorks.h>
37 #ifndef __RTP__
38 #include <vxLib.h>
39 #endif
40 #include <taskLib.h>
41 #ifndef __RTP__
42 #include <taskHookLib.h>
43 #else
44 # include <errno.h>
45 #endif
47 /* Init-once operation.
49 This would be a clone of the implementation from gthr-solaris.h,
50 except that we have a bootstrap problem - the whole point of this
51 exercise is to prevent double initialization, but if two threads
52 are racing with each other, once->mutex is liable to be initialized
53 by both. Then each thread will lock its own mutex, and proceed to
54 call the initialization routine.
56 So instead we use a bare atomic primitive (vxTas()) to handle
57 mutual exclusion. Threads losing the race then busy-wait, calling
58 taskDelay() to yield the processor, until the initialization is
59 completed. Inefficient, but reliable. */
61 int
62 __gthread_once (__gthread_once_t *guard, void (*func)(void))
64 if (guard->done)
65 return 0;
67 #ifdef __RTP__
68 __gthread_lock_library ();
69 #else
70 while (!vxTas ((void *)&guard->busy))
71 taskDelay (1);
72 #endif
74 /* Only one thread at a time gets here. Check ->done again, then
75 go ahead and call func() if no one has done it yet. */
76 if (!guard->done)
78 func ();
79 guard->done = 1;
82 #ifdef __RTP__
83 __gthread_unlock_library ();
84 #else
85 guard->busy = 0;
86 #endif
87 return 0;
90 /* Thread-local storage.
92 We reserve a field in the TCB to point to a dynamically allocated
93 array which is used to store TLS values. A TLS key is simply an
94 offset in this array. The exact location of the TCB field is not
95 known to this code nor to vxlib.c -- all access to it indirects
96 through the routines __gthread_get_tls_data and
97 __gthread_set_tls_data, which are provided by the VxWorks kernel.
99 There is also a global array which records which keys are valid and
100 which have destructors.
102 A task delete hook is installed to execute key destructors. The
103 routines __gthread_enter_tls_dtor_context and
104 __gthread_leave_tls_dtor_context, which are also provided by the
105 kernel, ensure that it is safe to call free() on memory allocated
106 by the task being deleted. (This is a no-op on VxWorks 5, but
107 a major undertaking on AE.)
109 The task delete hook is only installed when at least one thread
110 has TLS data. This is a necessary precaution, to allow this module
111 to be unloaded - a module with a hook can not be removed.
113 Since this interface is used to allocate only a small number of
114 keys, the table size is small and static, which simplifies the
115 code quite a bit. Revisit this if and when it becomes necessary. */
117 #define MAX_KEYS 4
119 /* This is the structure pointed to by the pointer returned
120 by __gthread_get_tls_data. */
121 struct tls_data
123 int *owner;
124 void *values[MAX_KEYS];
125 unsigned int generation[MAX_KEYS];
128 /* To make sure we only delete TLS data associated with this object,
129 include a pointer to a local variable in the TLS data object. */
130 static int self_owner;
132 /* The number of threads for this module which have active TLS data.
133 This is protected by tls_lock. */
134 static int active_tls_threads;
136 /* kernel provided routines */
137 extern void *__gthread_get_tls_data (void);
138 extern void __gthread_set_tls_data (void *data);
140 extern void __gthread_enter_tls_dtor_context (void);
141 extern void __gthread_leave_tls_dtor_context (void);
144 /* This is a global structure which records all of the active keys.
146 A key is potentially valid (i.e. has been handed out by
147 __gthread_key_create) iff its generation count in this structure is
148 even. In that case, the matching entry in the dtors array is a
149 routine to be called when a thread terminates with a valid,
150 non-NULL specific value for that key.
152 A key is actually valid in a thread T iff the generation count
153 stored in this structure is equal to the generation count stored in
154 T's specific-value structure. */
156 typedef void (*tls_dtor) (void *);
158 struct tls_keys
160 tls_dtor dtor[MAX_KEYS];
161 unsigned int generation[MAX_KEYS];
164 #define KEY_VALID_P(key) !(tls_keys.generation[key] & 1)
166 /* Note: if MAX_KEYS is increased, this initializer must be updated
167 to match. All the generation counts begin at 1, which means no
168 key is valid. */
169 static struct tls_keys tls_keys =
171 { 0, 0, 0, 0 },
172 { 1, 1, 1, 1 }
175 /* This lock protects the tls_keys structure. */
176 static __gthread_mutex_t tls_lock;
178 static __gthread_once_t tls_init_guard = __GTHREAD_ONCE_INIT;
180 /* Internal routines. */
182 /* The task TCB has just been deleted. Call the destructor
183 function for each TLS key that has both a destructor and
184 a non-NULL specific value in this thread.
186 This routine does not need to take tls_lock; the generation
187 count protects us from calling a stale destructor. It does
188 need to read tls_keys.dtor[key] atomically. */
190 static void
191 tls_delete_hook (void *tcb ATTRIBUTE_UNUSED)
193 struct tls_data *data = __gthread_get_tls_data ();
194 __gthread_key_t key;
196 if (data && data->owner == &self_owner)
198 __gthread_enter_tls_dtor_context ();
199 for (key = 0; key < MAX_KEYS; key++)
201 if (data->generation[key] == tls_keys.generation[key])
203 tls_dtor dtor = tls_keys.dtor[key];
205 if (dtor)
206 dtor (data->values[key]);
209 free (data);
211 /* We can't handle an error here, so just leave the thread
212 marked as loaded if one occurs. */
213 if (__gthread_mutex_lock (&tls_lock) != ERROR)
215 active_tls_threads--;
216 if (active_tls_threads == 0)
217 taskDeleteHookDelete ((FUNCPTR)tls_delete_hook);
218 __gthread_mutex_unlock (&tls_lock);
221 __gthread_set_tls_data (0);
222 __gthread_leave_tls_dtor_context ();
226 /* Initialize global data used by the TLS system. */
227 static void
228 tls_init (void)
230 __GTHREAD_MUTEX_INIT_FUNCTION (&tls_lock);
233 static void tls_destructor (void) __attribute__ ((destructor));
234 static void
235 tls_destructor (void)
237 #ifdef __RTP__
238 /* All threads but this one should have exited by now. */
239 tls_delete_hook (NULL);
240 #else
241 /* Unregister the hook forcibly. The counter of active threads may
242 be incorrect, because constructors (like the C++ library's) and
243 destructors (like this one) run in the context of the shell rather
244 than in a task spawned from this module. */
245 taskDeleteHookDelete ((FUNCPTR)tls_delete_hook);
246 #endif
248 if (tls_init_guard.done && __gthread_mutex_lock (&tls_lock) != ERROR)
249 semDelete (tls_lock);
252 /* External interface */
254 /* Store in KEYP a value which can be passed to __gthread_setspecific/
255 __gthread_getspecific to store and retrieve a value which is
256 specific to each calling thread. If DTOR is not NULL, it will be
257 called when a thread terminates with a non-NULL specific value for
258 this key, with the value as its sole argument. */
261 __gthread_key_create (__gthread_key_t *keyp, tls_dtor dtor)
263 __gthread_key_t key;
265 __gthread_once (&tls_init_guard, tls_init);
267 if (__gthread_mutex_lock (&tls_lock) == ERROR)
268 return errno;
270 for (key = 0; key < MAX_KEYS; key++)
271 if (!KEY_VALID_P (key))
272 goto found_slot;
274 /* no room */
275 __gthread_mutex_unlock (&tls_lock);
276 return EAGAIN;
278 found_slot:
279 tls_keys.generation[key]++; /* making it even */
280 tls_keys.dtor[key] = dtor;
281 *keyp = key;
282 __gthread_mutex_unlock (&tls_lock);
283 return 0;
286 /* Invalidate KEY; it can no longer be used as an argument to
287 setspecific/getspecific. Note that this does NOT call destructor
288 functions for any live values for this key. */
290 __gthread_key_delete (__gthread_key_t key)
292 if (key >= MAX_KEYS)
293 return EINVAL;
295 __gthread_once (&tls_init_guard, tls_init);
297 if (__gthread_mutex_lock (&tls_lock) == ERROR)
298 return errno;
300 if (!KEY_VALID_P (key))
302 __gthread_mutex_unlock (&tls_lock);
303 return EINVAL;
306 tls_keys.generation[key]++; /* making it odd */
307 tls_keys.dtor[key] = 0;
309 __gthread_mutex_unlock (&tls_lock);
310 return 0;
313 /* Retrieve the thread-specific value for KEY. If it has never been
314 set in this thread, or KEY is invalid, returns NULL.
316 It does not matter if this function races with key_create or
317 key_delete; the worst that can happen is you get a value other than
318 the one that a serialized implementation would have provided. */
320 void *
321 __gthread_getspecific (__gthread_key_t key)
323 struct tls_data *data;
325 if (key >= MAX_KEYS)
326 return 0;
328 data = __gthread_get_tls_data ();
330 if (!data)
331 return 0;
333 if (data->generation[key] != tls_keys.generation[key])
334 return 0;
336 return data->values[key];
339 /* Set the thread-specific value for KEY. If KEY is invalid, or
340 memory allocation fails, returns -1, otherwise 0.
342 The generation count protects this function against races with
343 key_create/key_delete; the worst thing that can happen is that a
344 value is successfully stored into a dead generation (and then
345 immediately becomes invalid). However, we do have to make sure
346 to read tls_keys.generation[key] atomically. */
349 __gthread_setspecific (__gthread_key_t key, void *value)
351 struct tls_data *data;
352 unsigned int generation;
354 if (key >= MAX_KEYS)
355 return EINVAL;
357 data = __gthread_get_tls_data ();
358 if (!data)
360 if (__gthread_mutex_lock (&tls_lock) == ERROR)
361 return ENOMEM;
362 if (active_tls_threads == 0)
363 taskDeleteHookAdd ((FUNCPTR)tls_delete_hook);
364 active_tls_threads++;
365 __gthread_mutex_unlock (&tls_lock);
367 data = malloc (sizeof (struct tls_data));
368 if (!data)
369 return ENOMEM;
371 memset (data, 0, sizeof (struct tls_data));
372 data->owner = &self_owner;
373 __gthread_set_tls_data (data);
376 generation = tls_keys.generation[key];
378 if (generation & 1)
379 return EINVAL;
381 data->generation[key] = generation;
382 data->values[key] = value;
384 return 0;
386 #endif /* __GTHREADS */