1 /* Thread-local storage in multithreaded situations. 2 Copyright (C) 2005, 2007-2020 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 <https://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 Equivalent functions with control of error handling: 29 Initialization: err = glthread_tls_key_init (&name, destructor); 30 Setting per-thread value: err = glthread_tls_set (&name, pointer); 31 De-initialization: err = glthread_tls_key_destroy (&name); 32 33 A per-thread value is of type 'void *'. 34 35 A destructor is a function pointer of type 'void (*) (void *)', called 36 when a thread exits, and taking the last per-thread value as argument. It 37 is unspecified whether the destructor function is called when the last 38 per-thread value is NULL. On some platforms, the destructor function is 39 not called at all. 40 */ 41 42 43 #ifndef _TLS_H 44 #define _TLS_H 45 46 #include <errno.h> 47 #include <stdlib.h> 48 49 #if !defined c11_threads_in_use 50 # if HAVE_THREADS_H && USE_POSIX_THREADS_WEAK 51 # include <threads.h> 52 # pragma weak thrd_exit 53 # define c11_threads_in_use() (thrd_exit != NULL) 54 # else 55 # define c11_threads_in_use() 0 56 # endif 57 #endif 58 59 /* ========================================================================= */ 60 61 #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS 62 63 /* Use the ISO C threads library. */ 64 65 # include <threads.h> 66 67 /* ------------------------- gl_tls_key_t datatype ------------------------- */ 68 69 typedef tss_t gl_tls_key_t; 70 # define glthread_tls_key_init(KEY, DESTRUCTOR) \ 71 (tss_create (KEY, DESTRUCTOR) != thrd_success ? EAGAIN : 0) 72 # define gl_tls_get(NAME) \ 73 tss_get (NAME) 74 # define glthread_tls_set(KEY, POINTER) \ 75 (tss_set (*(KEY), (POINTER)) != thrd_success ? ENOMEM : 0) 76 # define glthread_tls_key_destroy(KEY) \ 77 (tss_delete (*(KEY)), 0) 78 79 #endif 80 81 /* ========================================================================= */ 82 83 #if USE_POSIX_THREADS 84 85 /* Use the POSIX threads library. */ 86 87 # include <pthread.h> 88 89 # if PTHREAD_IN_USE_DETECTION_HARD 90 91 /* The pthread_in_use() detection needs to be done at runtime. */ 92 # define pthread_in_use() \ 93 glthread_in_use () 94 extern int glthread_in_use (void); 95 96 # endif 97 98 # if USE_POSIX_THREADS_WEAK 99 100 /* Use weak references to the POSIX threads library. */ 101 102 # pragma weak pthread_key_create 103 # pragma weak pthread_getspecific 104 # pragma weak pthread_setspecific 105 # pragma weak pthread_key_delete 106 # ifndef pthread_self 107 # pragma weak pthread_self 108 # endif 109 110 # if !PTHREAD_IN_USE_DETECTION_HARD 111 # pragma weak pthread_mutexattr_gettype 112 # define pthread_in_use() \ 113 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ()) 114 # endif 115 116 # else 117 118 # if !PTHREAD_IN_USE_DETECTION_HARD 119 # define pthread_in_use() 1 120 # endif 121 122 # endif 123 124 /* ------------------------- gl_tls_key_t datatype ------------------------- */ 125 126 typedef union 127 { 128 void *singlethread_value; 129 pthread_key_t key; 130 } 131 gl_tls_key_t; 132 # define glthread_tls_key_init(KEY, DESTRUCTOR) \ 133 (pthread_in_use () \ 134 ? pthread_key_create (&(KEY)->key, DESTRUCTOR) \ 135 : ((KEY)->singlethread_value = NULL, 0)) 136 # define gl_tls_get(NAME) \ 137 (pthread_in_use () \ 138 ? pthread_getspecific ((NAME).key) \ 139 : (NAME).singlethread_value) 140 # define glthread_tls_set(KEY, POINTER) \ 141 (pthread_in_use () \ 142 ? pthread_setspecific ((KEY)->key, (POINTER)) \ 143 : ((KEY)->singlethread_value = (POINTER), 0)) 144 # define glthread_tls_key_destroy(KEY) \ 145 (pthread_in_use () ? pthread_key_delete ((KEY)->key) : 0) 146 147 #endif 148 149 /* ========================================================================= */ 150 151 #if USE_WINDOWS_THREADS 152 153 # define WIN32_LEAN_AND_MEAN /* avoid including junk */ 154 # include <windows.h> 155 156 # include "windows-tls.h" 157 158 /* ------------------------- gl_tls_key_t datatype ------------------------- */ 159 160 typedef glwthread_tls_key_t gl_tls_key_t; 161 # define glthread_tls_key_init(KEY, DESTRUCTOR) \ 162 glwthread_tls_key_create (KEY, DESTRUCTOR) 163 # define gl_tls_get(NAME) \ 164 TlsGetValue (NAME) 165 # define glthread_tls_set(KEY, POINTER) \ 166 (!TlsSetValue (*(KEY), POINTER) ? EINVAL : 0) 167 # define glthread_tls_key_destroy(KEY) \ 168 glwthread_tls_key_delete (*(KEY)) 169 170 #endif 171 172 /* ========================================================================= */ 173 174 #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS) 175 176 /* Provide dummy implementation if threads are not supported. */ 177 178 /* ------------------------- gl_tls_key_t datatype ------------------------- */ 179 180 typedef struct 181 { 182 void *singlethread_value; 183 } 184 gl_tls_key_t; 185 # define glthread_tls_key_init(KEY, DESTRUCTOR) \ 186 ((KEY)->singlethread_value = NULL, \ 187 (void) (DESTRUCTOR), \ 188 0) 189 # define gl_tls_get(NAME) \ 190 (NAME).singlethread_value 191 # define glthread_tls_set(KEY, POINTER) \ 192 ((KEY)->singlethread_value = (POINTER), 0) 193 # define glthread_tls_key_destroy(KEY) \ 194 0 195 196 #endif 197 198 /* ========================================================================= */ 199 200 /* Macros with built-in error handling. */ 201 202 /* ------------------------- gl_tls_key_t datatype ------------------------- */ 203 204 #define gl_tls_key_init(NAME, DESTRUCTOR) \ 205 do \ 206 { \ 207 if (glthread_tls_key_init (&NAME, DESTRUCTOR)) \ 208 abort (); \ 209 } \ 210 while (0) 211 #define gl_tls_set(NAME, POINTER) \ 212 do \ 213 { \ 214 if (glthread_tls_set (&NAME, POINTER)) \ 215 abort (); \ 216 } \ 217 while (0) 218 #define gl_tls_key_destroy(NAME) \ 219 do \ 220 { \ 221 if (glthread_tls_key_destroy (&NAME)) \ 222 abort (); \ 223 } \ 224 while (0) 225 226 /* ========================================================================= */ 227 228 #endif /* _TLS_H */ 229