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