1/* Thread-local storage in multithreaded situations. 2 Copyright (C) 2005, 2007 Free Software Foundation, Inc. 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17/* Written by Bruno Haible <bruno@clisp.org>, 2005. */ 18 19/* This file contains thread-local storage primitives for use with a given 20 thread library. It does not contain primitives for creating threads or 21 for other multithreading primitives. 22 23 Type: gl_tls_key_t 24 Initialization: gl_tls_key_init (name, destructor); 25 Getting per-thread value: gl_tls_get (name) 26 Setting per-thread value: gl_tls_set (name, pointer); 27 De-initialization: gl_tls_key_destroy (name); 28 29 A per-thread value is of type 'void *'. 30 31 A destructor is a function pointer of type 'void (*) (void *)', called 32 when a thread exits, and taking the last per-thread value as argument. It 33 is unspecified whether the destructor function is called when the last 34 per-thread value is NULL. On some platforms, the destructor function is 35 not called at all. 36*/ 37 38 39#ifndef _TLS_H 40#define _TLS_H 41 42/* ========================================================================= */ 43 44#if USE_POSIX_THREADS 45 46/* Use the POSIX threads library. */ 47 48# include <pthread.h> 49# include <stdlib.h> 50 51# if PTHREAD_IN_USE_DETECTION_HARD 52 53/* The pthread_in_use() detection needs to be done at runtime. */ 54# define pthread_in_use() \ 55 glthread_in_use () 56extern int glthread_in_use (void); 57 58# endif 59 60# if USE_POSIX_THREADS_WEAK 61 62/* Use weak references to the POSIX threads library. */ 63 64# pragma weak pthread_key_create 65# pragma weak pthread_getspecific 66# pragma weak pthread_setspecific 67# pragma weak pthread_key_delete 68# ifndef pthread_self 69# pragma weak pthread_self 70# endif 71 72# if !PTHREAD_IN_USE_DETECTION_HARD 73# pragma weak pthread_cancel 74# define pthread_in_use() (pthread_cancel != NULL) 75# endif 76 77# else 78 79# if !PTHREAD_IN_USE_DETECTION_HARD 80# define pthread_in_use() 1 81# endif 82 83# endif 84 85/* ------------------------- gl_tls_key_t datatype ------------------------- */ 86 87typedef union 88 { 89 void *singlethread_value; 90 pthread_key_t key; 91 } 92 gl_tls_key_t; 93# define gl_tls_key_init(NAME, DESTRUCTOR) \ 94 do \ 95 { \ 96 if (pthread_in_use ()) \ 97 { \ 98 if (pthread_key_create (&(NAME).key, DESTRUCTOR) != 0) \ 99 abort (); \ 100 } \ 101 else \ 102 (NAME).singlethread_value = NULL; \ 103 } \ 104 while (0) 105# define gl_tls_get(NAME) \ 106 (pthread_in_use () \ 107 ? pthread_getspecific ((NAME).key) \ 108 : (NAME).singlethread_value) 109# define gl_tls_set(NAME, POINTER) \ 110 do \ 111 { \ 112 if (pthread_in_use ()) \ 113 { \ 114 if (pthread_setspecific ((NAME).key, (POINTER)) != 0) \ 115 abort (); \ 116 } \ 117 else \ 118 (NAME).singlethread_value = (POINTER); \ 119 } \ 120 while (0) 121# define gl_tls_key_destroy(NAME) \ 122 do \ 123 { \ 124 if (pthread_in_use () && pthread_key_delete ((NAME).key) != 0) \ 125 abort (); \ 126 } \ 127 while (0) 128 129#endif 130 131/* ========================================================================= */ 132 133#if USE_PTH_THREADS 134 135/* Use the GNU Pth threads library. */ 136 137# include <pth.h> 138# include <stdlib.h> 139 140# if USE_PTH_THREADS_WEAK 141 142/* Use weak references to the GNU Pth threads library. */ 143 144# pragma weak pth_key_create 145# pragma weak pth_key_getdata 146# pragma weak pth_key_setdata 147# pragma weak pth_key_delete 148 149# pragma weak pth_cancel 150# define pth_in_use() (pth_cancel != NULL) 151 152# else 153 154# define pth_in_use() 1 155 156# endif 157 158/* ------------------------- gl_tls_key_t datatype ------------------------- */ 159 160typedef union 161 { 162 void *singlethread_value; 163 pth_key_t key; 164 } 165 gl_tls_key_t; 166# define gl_tls_key_init(NAME, DESTRUCTOR) \ 167 do \ 168 { \ 169 if (pth_in_use ()) \ 170 { \ 171 if (!pth_key_create (&(NAME).key, DESTRUCTOR)) \ 172 abort (); \ 173 } \ 174 else \ 175 (NAME).singlethread_value = NULL; \ 176 } \ 177 while (0) 178# define gl_tls_get(NAME) \ 179 (pth_in_use () \ 180 ? pth_key_getdata ((NAME).key) \ 181 : (NAME).singlethread_value) 182# define gl_tls_set(NAME, POINTER) \ 183 do \ 184 { \ 185 if (pth_in_use ()) \ 186 { \ 187 if (!pth_key_setdata ((NAME).key, (POINTER))) \ 188 abort (); \ 189 } \ 190 else \ 191 (NAME).singlethread_value = (POINTER); \ 192 } \ 193 while (0) 194# define gl_tls_key_destroy(NAME) \ 195 do \ 196 { \ 197 if (pth_in_use () && !pth_key_delete ((NAME).key)) \ 198 abort (); \ 199 } \ 200 while (0) 201 202#endif 203 204/* ========================================================================= */ 205 206#if USE_SOLARIS_THREADS 207 208/* Use the old Solaris threads library. */ 209 210# include <thread.h> 211# include <stdlib.h> 212 213# if USE_SOLARIS_THREADS_WEAK 214 215/* Use weak references to the old Solaris threads library. */ 216 217# pragma weak thr_keycreate 218# pragma weak thr_getspecific 219# pragma weak thr_setspecific 220 221# pragma weak thr_suspend 222# define thread_in_use() (thr_suspend != NULL) 223 224# else 225 226# define thread_in_use() 1 227 228# endif 229 230/* ------------------------- gl_tls_key_t datatype ------------------------- */ 231 232typedef union 233 { 234 void *singlethread_value; 235 thread_key_t key; 236 } 237 gl_tls_key_t; 238# define gl_tls_key_init(NAME, DESTRUCTOR) \ 239 do \ 240 { \ 241 if (thread_in_use ()) \ 242 { \ 243 if (thr_keycreate (&(NAME).key, DESTRUCTOR) != 0) \ 244 abort (); \ 245 } \ 246 else \ 247 (NAME).singlethread_value = NULL; \ 248 } \ 249 while (0) 250# define gl_tls_get(NAME) \ 251 (thread_in_use () \ 252 ? glthread_tls_get ((NAME).key) \ 253 : (NAME).singlethread_value) 254extern void *glthread_tls_get (thread_key_t key); 255# define gl_tls_set(NAME, POINTER) \ 256 do \ 257 { \ 258 if (thread_in_use ()) \ 259 { \ 260 if (thr_setspecific ((NAME).key, (POINTER)) != 0) \ 261 abort (); \ 262 } \ 263 else \ 264 (NAME).singlethread_value = (POINTER); \ 265 } \ 266 while (0) 267# define gl_tls_key_destroy(NAME) \ 268 /* Unsupported. */ \ 269 (void)0 270 271#endif 272 273/* ========================================================================= */ 274 275#if USE_WIN32_THREADS 276 277# include <windows.h> 278 279/* ------------------------- gl_tls_key_t datatype ------------------------- */ 280 281typedef DWORD gl_tls_key_t; 282# define gl_tls_key_init(NAME, DESTRUCTOR) \ 283 /* The destructor is unsupported. */ \ 284 do \ 285 { \ 286 if (((NAME) = TlsAlloc ()) == (DWORD)-1) \ 287 abort (); \ 288 } \ 289 while (0) 290# define gl_tls_get(NAME) \ 291 TlsGetValue (NAME) 292# define gl_tls_set(NAME, POINTER) \ 293 do \ 294 { \ 295 if (!TlsSetValue (NAME, POINTER)) \ 296 abort (); \ 297 } \ 298 while (0) 299# define gl_tls_key_destroy(NAME) \ 300 do \ 301 { \ 302 if (!TlsFree (NAME)) \ 303 abort (); \ 304 } \ 305 while (0) 306 307#endif 308 309/* ========================================================================= */ 310 311#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS) 312 313/* Provide dummy implementation if threads are not supported. */ 314 315/* ------------------------- gl_tls_key_t datatype ------------------------- */ 316 317typedef struct 318 { 319 void *singlethread_value; 320 } 321 gl_tls_key_t; 322# define gl_tls_key_init(NAME, DESTRUCTOR) \ 323 (NAME).singlethread_value = NULL 324# define gl_tls_get(NAME) \ 325 (NAME).singlethread_value 326# define gl_tls_set(NAME, POINTER) \ 327 (NAME).singlethread_value = (POINTER) 328# define gl_tls_key_destroy(NAME) \ 329 (void)0 330 331#endif 332 333/* ========================================================================= */ 334 335#endif /* _TLS_H */ 336