1169689Skan/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 2132718Skan Contributed by Zack Weinberg <zack@codesourcery.com> 3132718Skan 4132718SkanThis file is part of GCC. 5132718Skan 6132718SkanGCC is free software; you can redistribute it and/or modify it under 7132718Skanthe terms of the GNU General Public License as published by the Free 8132718SkanSoftware Foundation; either version 2, or (at your option) any later 9132718Skanversion. 10132718Skan 11132718SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 12132718SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 13132718SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14132718Skanfor more details. 15132718Skan 16132718SkanYou should have received a copy of the GNU General Public License 17132718Skanalong with GCC; see the file COPYING. If not, write to the Free 18169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 19169689Skan02110-1301, USA. */ 20132718Skan 21132718Skan/* As a special exception, if you link this library with other files, 22132718Skan some of which are compiled with GCC, to produce an executable, 23132718Skan this library does not by itself cause the resulting executable 24132718Skan to be covered by the GNU General Public License. 25132718Skan This exception does not however invalidate any other reasons why 26132718Skan the executable file might be covered by the GNU General Public License. */ 27132718Skan 28169689Skan/* Threads compatibility routines for libgcc2 for VxWorks. 29169689Skan These are out-of-line routines called from gthr-vxworks.h. */ 30169689Skan 31132718Skan#include "tconfig.h" 32132718Skan#include "tsystem.h" 33132718Skan#include "gthr.h" 34132718Skan 35169689Skan#if defined(__GTHREADS) 36132718Skan#include <vxWorks.h> 37169689Skan#ifndef __RTP__ 38132718Skan#include <vxLib.h> 39169689Skan#endif 40132718Skan#include <taskLib.h> 41169689Skan#ifndef __RTP__ 42132718Skan#include <taskHookLib.h> 43169689Skan#else 44169689Skan# include <errno.h> 45169689Skan#endif 46132718Skan 47132718Skan/* Init-once operation. 48132718Skan 49132718Skan This would be a clone of the implementation from gthr-solaris.h, 50132718Skan except that we have a bootstrap problem - the whole point of this 51132718Skan exercise is to prevent double initialization, but if two threads 52132718Skan are racing with each other, once->mutex is liable to be initialized 53132718Skan by both. Then each thread will lock its own mutex, and proceed to 54132718Skan call the initialization routine. 55132718Skan 56132718Skan So instead we use a bare atomic primitive (vxTas()) to handle 57132718Skan mutual exclusion. Threads losing the race then busy-wait, calling 58132718Skan taskDelay() to yield the processor, until the initialization is 59132718Skan completed. Inefficient, but reliable. */ 60132718Skan 61132718Skanint 62132718Skan__gthread_once (__gthread_once_t *guard, void (*func)(void)) 63132718Skan{ 64132718Skan if (guard->done) 65132718Skan return 0; 66132718Skan 67169689Skan#ifdef __RTP__ 68169689Skan __gthread_lock_library (); 69169689Skan#else 70132718Skan while (!vxTas ((void *)&guard->busy)) 71132718Skan taskDelay (1); 72169689Skan#endif 73132718Skan 74132718Skan /* Only one thread at a time gets here. Check ->done again, then 75132718Skan go ahead and call func() if no one has done it yet. */ 76132718Skan if (!guard->done) 77132718Skan { 78132718Skan func (); 79132718Skan guard->done = 1; 80132718Skan } 81132718Skan 82169689Skan#ifdef __RTP__ 83169689Skan __gthread_unlock_library (); 84169689Skan#else 85132718Skan guard->busy = 0; 86169689Skan#endif 87132718Skan return 0; 88132718Skan} 89132718Skan 90169689Skan/* Thread-local storage. 91132718Skan 92132718Skan We reserve a field in the TCB to point to a dynamically allocated 93169689Skan array which is used to store TLS values. A TLS key is simply an 94132718Skan offset in this array. The exact location of the TCB field is not 95132718Skan known to this code nor to vxlib.c -- all access to it indirects 96169689Skan through the routines __gthread_get_tls_data and 97169689Skan __gthread_set_tls_data, which are provided by the VxWorks kernel. 98132718Skan 99132718Skan There is also a global array which records which keys are valid and 100132718Skan which have destructors. 101132718Skan 102132718Skan A task delete hook is installed to execute key destructors. The 103169689Skan routines __gthread_enter_tls_dtor_context and 104169689Skan __gthread_leave_tls_dtor_context, which are also provided by the 105132718Skan kernel, ensure that it is safe to call free() on memory allocated 106132718Skan by the task being deleted. (This is a no-op on VxWorks 5, but 107132718Skan a major undertaking on AE.) 108132718Skan 109169689Skan The task delete hook is only installed when at least one thread 110169689Skan has TLS data. This is a necessary precaution, to allow this module 111169689Skan to be unloaded - a module with a hook can not be removed. 112169689Skan 113132718Skan Since this interface is used to allocate only a small number of 114132718Skan keys, the table size is small and static, which simplifies the 115132718Skan code quite a bit. Revisit this if and when it becomes necessary. */ 116132718Skan 117132718Skan#define MAX_KEYS 4 118132718Skan 119132718Skan/* This is the structure pointed to by the pointer returned 120169689Skan by __gthread_get_tls_data. */ 121169689Skanstruct tls_data 122132718Skan{ 123169689Skan int *owner; 124132718Skan void *values[MAX_KEYS]; 125132718Skan unsigned int generation[MAX_KEYS]; 126132718Skan}; 127132718Skan 128169689Skan/* To make sure we only delete TLS data associated with this object, 129169689Skan include a pointer to a local variable in the TLS data object. */ 130169689Skanstatic int self_owner; 131132718Skan 132169689Skan/* The number of threads for this module which have active TLS data. 133169689Skan This is protected by tls_lock. */ 134169689Skanstatic int active_tls_threads; 135169689Skan 136132718Skan/* kernel provided routines */ 137169689Skanextern void *__gthread_get_tls_data (void); 138169689Skanextern void __gthread_set_tls_data (void *data); 139132718Skan 140169689Skanextern void __gthread_enter_tls_dtor_context (void); 141169689Skanextern void __gthread_leave_tls_dtor_context (void); 142132718Skan 143132718Skan 144132718Skan/* This is a global structure which records all of the active keys. 145132718Skan 146132718Skan A key is potentially valid (i.e. has been handed out by 147132718Skan __gthread_key_create) iff its generation count in this structure is 148132718Skan even. In that case, the matching entry in the dtors array is a 149132718Skan routine to be called when a thread terminates with a valid, 150132718Skan non-NULL specific value for that key. 151132718Skan 152132718Skan A key is actually valid in a thread T iff the generation count 153132718Skan stored in this structure is equal to the generation count stored in 154132718Skan T's specific-value structure. */ 155132718Skan 156169689Skantypedef void (*tls_dtor) (void *); 157132718Skan 158169689Skanstruct tls_keys 159132718Skan{ 160169689Skan tls_dtor dtor[MAX_KEYS]; 161132718Skan unsigned int generation[MAX_KEYS]; 162132718Skan}; 163132718Skan 164169689Skan#define KEY_VALID_P(key) !(tls_keys.generation[key] & 1) 165132718Skan 166132718Skan/* Note: if MAX_KEYS is increased, this initializer must be updated 167132718Skan to match. All the generation counts begin at 1, which means no 168132718Skan key is valid. */ 169169689Skanstatic struct tls_keys tls_keys = 170132718Skan{ 171132718Skan { 0, 0, 0, 0 }, 172132718Skan { 1, 1, 1, 1 } 173132718Skan}; 174132718Skan 175169689Skan/* This lock protects the tls_keys structure. */ 176169689Skanstatic __gthread_mutex_t tls_lock; 177132718Skan 178169689Skanstatic __gthread_once_t tls_init_guard = __GTHREAD_ONCE_INIT; 179132718Skan 180132718Skan/* Internal routines. */ 181132718Skan 182132718Skan/* The task TCB has just been deleted. Call the destructor 183169689Skan function for each TLS key that has both a destructor and 184132718Skan a non-NULL specific value in this thread. 185132718Skan 186169689Skan This routine does not need to take tls_lock; the generation 187132718Skan count protects us from calling a stale destructor. It does 188169689Skan need to read tls_keys.dtor[key] atomically. */ 189132718Skan 190132718Skanstatic void 191169689Skantls_delete_hook (void *tcb ATTRIBUTE_UNUSED) 192132718Skan{ 193169689Skan struct tls_data *data = __gthread_get_tls_data (); 194132718Skan __gthread_key_t key; 195132718Skan 196169689Skan if (data && data->owner == &self_owner) 197132718Skan { 198169689Skan __gthread_enter_tls_dtor_context (); 199132718Skan for (key = 0; key < MAX_KEYS; key++) 200132718Skan { 201169689Skan if (data->generation[key] == tls_keys.generation[key]) 202132718Skan { 203169689Skan tls_dtor dtor = tls_keys.dtor[key]; 204132718Skan 205132718Skan if (dtor) 206132718Skan dtor (data->values[key]); 207132718Skan } 208132718Skan } 209132718Skan free (data); 210169689Skan 211169689Skan /* We can't handle an error here, so just leave the thread 212169689Skan marked as loaded if one occurs. */ 213169689Skan if (__gthread_mutex_lock (&tls_lock) != ERROR) 214169689Skan { 215169689Skan active_tls_threads--; 216169689Skan if (active_tls_threads == 0) 217169689Skan taskDeleteHookDelete ((FUNCPTR)tls_delete_hook); 218169689Skan __gthread_mutex_unlock (&tls_lock); 219169689Skan } 220169689Skan 221169689Skan __gthread_set_tls_data (0); 222169689Skan __gthread_leave_tls_dtor_context (); 223132718Skan } 224132718Skan} 225132718Skan 226169689Skan/* Initialize global data used by the TLS system. */ 227132718Skanstatic void 228169689Skantls_init (void) 229132718Skan{ 230169689Skan __GTHREAD_MUTEX_INIT_FUNCTION (&tls_lock); 231132718Skan} 232132718Skan 233169689Skanstatic void tls_destructor (void) __attribute__ ((destructor)); 234169689Skanstatic void 235169689Skantls_destructor (void) 236169689Skan{ 237169689Skan#ifdef __RTP__ 238169689Skan /* All threads but this one should have exited by now. */ 239169689Skan tls_delete_hook (NULL); 240169689Skan#else 241169689Skan /* Unregister the hook forcibly. The counter of active threads may 242169689Skan be incorrect, because constructors (like the C++ library's) and 243169689Skan destructors (like this one) run in the context of the shell rather 244169689Skan than in a task spawned from this module. */ 245169689Skan taskDeleteHookDelete ((FUNCPTR)tls_delete_hook); 246169689Skan#endif 247169689Skan 248169689Skan if (tls_init_guard.done && __gthread_mutex_lock (&tls_lock) != ERROR) 249169689Skan semDelete (tls_lock); 250169689Skan} 251169689Skan 252132718Skan/* External interface */ 253132718Skan 254132718Skan/* Store in KEYP a value which can be passed to __gthread_setspecific/ 255132718Skan __gthread_getspecific to store and retrieve a value which is 256132718Skan specific to each calling thread. If DTOR is not NULL, it will be 257132718Skan called when a thread terminates with a non-NULL specific value for 258132718Skan this key, with the value as its sole argument. */ 259132718Skan 260132718Skanint 261169689Skan__gthread_key_create (__gthread_key_t *keyp, tls_dtor dtor) 262132718Skan{ 263132718Skan __gthread_key_t key; 264132718Skan 265169689Skan __gthread_once (&tls_init_guard, tls_init); 266132718Skan 267169689Skan if (__gthread_mutex_lock (&tls_lock) == ERROR) 268132718Skan return errno; 269132718Skan 270132718Skan for (key = 0; key < MAX_KEYS; key++) 271132718Skan if (!KEY_VALID_P (key)) 272132718Skan goto found_slot; 273132718Skan 274132718Skan /* no room */ 275169689Skan __gthread_mutex_unlock (&tls_lock); 276132718Skan return EAGAIN; 277132718Skan 278132718Skan found_slot: 279169689Skan tls_keys.generation[key]++; /* making it even */ 280169689Skan tls_keys.dtor[key] = dtor; 281132718Skan *keyp = key; 282169689Skan __gthread_mutex_unlock (&tls_lock); 283132718Skan return 0; 284132718Skan} 285132718Skan 286132718Skan/* Invalidate KEY; it can no longer be used as an argument to 287132718Skan setspecific/getspecific. Note that this does NOT call destructor 288132718Skan functions for any live values for this key. */ 289132718Skanint 290132718Skan__gthread_key_delete (__gthread_key_t key) 291132718Skan{ 292132718Skan if (key >= MAX_KEYS) 293132718Skan return EINVAL; 294132718Skan 295169689Skan __gthread_once (&tls_init_guard, tls_init); 296132718Skan 297169689Skan if (__gthread_mutex_lock (&tls_lock) == ERROR) 298132718Skan return errno; 299132718Skan 300132718Skan if (!KEY_VALID_P (key)) 301132718Skan { 302169689Skan __gthread_mutex_unlock (&tls_lock); 303132718Skan return EINVAL; 304132718Skan } 305132718Skan 306169689Skan tls_keys.generation[key]++; /* making it odd */ 307169689Skan tls_keys.dtor[key] = 0; 308132718Skan 309169689Skan __gthread_mutex_unlock (&tls_lock); 310132718Skan return 0; 311132718Skan} 312132718Skan 313132718Skan/* Retrieve the thread-specific value for KEY. If it has never been 314132718Skan set in this thread, or KEY is invalid, returns NULL. 315132718Skan 316132718Skan It does not matter if this function races with key_create or 317132718Skan key_delete; the worst that can happen is you get a value other than 318132718Skan the one that a serialized implementation would have provided. */ 319132718Skan 320132718Skanvoid * 321132718Skan__gthread_getspecific (__gthread_key_t key) 322132718Skan{ 323169689Skan struct tls_data *data; 324132718Skan 325132718Skan if (key >= MAX_KEYS) 326132718Skan return 0; 327132718Skan 328169689Skan data = __gthread_get_tls_data (); 329132718Skan 330132718Skan if (!data) 331132718Skan return 0; 332132718Skan 333169689Skan if (data->generation[key] != tls_keys.generation[key]) 334132718Skan return 0; 335132718Skan 336132718Skan return data->values[key]; 337132718Skan} 338132718Skan 339132718Skan/* Set the thread-specific value for KEY. If KEY is invalid, or 340132718Skan memory allocation fails, returns -1, otherwise 0. 341132718Skan 342132718Skan The generation count protects this function against races with 343132718Skan key_create/key_delete; the worst thing that can happen is that a 344132718Skan value is successfully stored into a dead generation (and then 345132718Skan immediately becomes invalid). However, we do have to make sure 346169689Skan to read tls_keys.generation[key] atomically. */ 347132718Skan 348132718Skanint 349132718Skan__gthread_setspecific (__gthread_key_t key, void *value) 350132718Skan{ 351169689Skan struct tls_data *data; 352132718Skan unsigned int generation; 353132718Skan 354132718Skan if (key >= MAX_KEYS) 355132718Skan return EINVAL; 356132718Skan 357169689Skan data = __gthread_get_tls_data (); 358132718Skan if (!data) 359132718Skan { 360169689Skan if (__gthread_mutex_lock (&tls_lock) == ERROR) 361169689Skan return ENOMEM; 362169689Skan if (active_tls_threads == 0) 363169689Skan taskDeleteHookAdd ((FUNCPTR)tls_delete_hook); 364169689Skan active_tls_threads++; 365169689Skan __gthread_mutex_unlock (&tls_lock); 366169689Skan 367169689Skan data = malloc (sizeof (struct tls_data)); 368132718Skan if (!data) 369132718Skan return ENOMEM; 370132718Skan 371169689Skan memset (data, 0, sizeof (struct tls_data)); 372169689Skan data->owner = &self_owner; 373169689Skan __gthread_set_tls_data (data); 374132718Skan } 375132718Skan 376169689Skan generation = tls_keys.generation[key]; 377132718Skan 378132718Skan if (generation & 1) 379132718Skan return EINVAL; 380132718Skan 381132718Skan data->generation[key] = generation; 382132718Skan data->values[key] = value; 383132718Skan 384132718Skan return 0; 385132718Skan} 386169689Skan#endif /* __GTHREADS */ 387