1 1.8 mrg /* Copyright (C) 2002-2019 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.8 mrg to be unloaded - a module with a hook cannot 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