1 /* Thread-local storage in multithreaded situations. 2 Copyright (C) 2005, 2007-2021 Free Software Foundation, Inc. 3 4 This file is free software: you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 2.1 of the 7 License, or (at your option) any later version. 8 9 This file 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 Lesser General Public License for more details. 13 14 You should have received a copy of the GNU Lesser 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_FROM_LIBC 51 # define c11_threads_in_use() 1 52 # elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK 53 # include <threads.h> 54 # pragma weak thrd_exit 55 # define c11_threads_in_use() (thrd_exit != NULL) 56 # else 57 # define c11_threads_in_use() 0 58 # endif 59 #endif 60 61 /* ========================================================================= */ 62 63 #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS 64 65 /* Use the ISO C threads library. */ 66 67 # include <threads.h> 68 69 /* ------------------------- gl_tls_key_t datatype ------------------------- */ 70 71 typedef tss_t gl_tls_key_t; 72 # define glthread_tls_key_init(KEY, DESTRUCTOR) \ 73 (tss_create (KEY, DESTRUCTOR) != thrd_success ? EAGAIN : 0) 74 # define gl_tls_get(NAME) \ 75 tss_get (NAME) 76 # define glthread_tls_set(KEY, POINTER) \ 77 (tss_set (*(KEY), (POINTER)) != thrd_success ? ENOMEM : 0) 78 # define glthread_tls_key_destroy(KEY) \ 79 (tss_delete (*(KEY)), 0) 80 81 #endif 82 83 /* ========================================================================= */ 84 85 #if USE_POSIX_THREADS 86 87 /* Use the POSIX threads library. */ 88 89 # include <pthread.h> 90 91 # if PTHREAD_IN_USE_DETECTION_HARD 92 93 /* The pthread_in_use() detection needs to be done at runtime. */ 94 # define pthread_in_use() \ 95 glthread_in_use () 96 extern int glthread_in_use (void); 97 98 # endif 99 100 # if USE_POSIX_THREADS_WEAK 101 102 /* Use weak references to the POSIX threads library. */ 103 104 # pragma weak pthread_key_create 105 # pragma weak pthread_getspecific 106 # pragma weak pthread_setspecific 107 # pragma weak pthread_key_delete 108 # ifndef pthread_self 109 # pragma weak pthread_self 110 # endif 111 112 # if !PTHREAD_IN_USE_DETECTION_HARD 113 # pragma weak pthread_mutexattr_gettype 114 # define pthread_in_use() \ 115 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ()) 116 # endif 117 118 # else 119 120 # if !PTHREAD_IN_USE_DETECTION_HARD 121 # define pthread_in_use() 1 122 # endif 123 124 # endif 125 126 /* ------------------------- gl_tls_key_t datatype ------------------------- */ 127 128 typedef union 129 { 130 void *singlethread_value; 131 pthread_key_t key; 132 } 133 gl_tls_key_t; 134 # define glthread_tls_key_init(KEY, DESTRUCTOR) \ 135 (pthread_in_use () \ 136 ? pthread_key_create (&(KEY)->key, DESTRUCTOR) \ 137 : ((KEY)->singlethread_value = NULL, 0)) 138 # define gl_tls_get(NAME) \ 139 (pthread_in_use () \ 140 ? pthread_getspecific ((NAME).key) \ 141 : (NAME).singlethread_value) 142 # define glthread_tls_set(KEY, POINTER) \ 143 (pthread_in_use () \ 144 ? pthread_setspecific ((KEY)->key, (POINTER)) \ 145 : ((KEY)->singlethread_value = (POINTER), 0)) 146 # define glthread_tls_key_destroy(KEY) \ 147 (pthread_in_use () ? pthread_key_delete ((KEY)->key) : 0) 148 149 #endif 150 151 /* ========================================================================= */ 152 153 #if USE_WINDOWS_THREADS 154 155 # define WIN32_LEAN_AND_MEAN /* avoid including junk */ 156 # include <windows.h> 157 158 # include "windows-tls.h" 159 160 /* ------------------------- gl_tls_key_t datatype ------------------------- */ 161 162 typedef glwthread_tls_key_t gl_tls_key_t; 163 # define glthread_tls_key_init(KEY, DESTRUCTOR) \ 164 glwthread_tls_key_create (KEY, DESTRUCTOR) 165 # define gl_tls_get(NAME) \ 166 TlsGetValue (NAME) 167 # define glthread_tls_set(KEY, POINTER) \ 168 (!TlsSetValue (*(KEY), POINTER) ? EINVAL : 0) 169 # define glthread_tls_key_destroy(KEY) \ 170 glwthread_tls_key_delete (*(KEY)) 171 172 #endif 173 174 /* ========================================================================= */ 175 176 #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS) 177 178 /* Provide dummy implementation if threads are not supported. */ 179 180 /* ------------------------- gl_tls_key_t datatype ------------------------- */ 181 182 typedef struct 183 { 184 void *singlethread_value; 185 } 186 gl_tls_key_t; 187 # define glthread_tls_key_init(KEY, DESTRUCTOR) \ 188 ((KEY)->singlethread_value = NULL, \ 189 (void) (DESTRUCTOR), \ 190 0) 191 # define gl_tls_get(NAME) \ 192 (NAME).singlethread_value 193 # define glthread_tls_set(KEY, POINTER) \ 194 ((KEY)->singlethread_value = (POINTER), 0) 195 # define glthread_tls_key_destroy(KEY) \ 196 0 197 198 #endif 199 200 /* ========================================================================= */ 201 202 /* Macros with built-in error handling. */ 203 204 /* ------------------------- gl_tls_key_t datatype ------------------------- */ 205 206 #define gl_tls_key_init(NAME, DESTRUCTOR) \ 207 do \ 208 { \ 209 if (glthread_tls_key_init (&NAME, DESTRUCTOR)) \ 210 abort (); \ 211 } \ 212 while (0) 213 #define gl_tls_set(NAME, POINTER) \ 214 do \ 215 { \ 216 if (glthread_tls_set (&NAME, POINTER)) \ 217 abort (); \ 218 } \ 219 while (0) 220 #define gl_tls_key_destroy(NAME) \ 221 do \ 222 { \ 223 if (glthread_tls_key_destroy (&NAME)) \ 224 abort (); \ 225 } \ 226 while (0) 227 228 /* ========================================================================= */ 229 230 #endif /* _TLS_H */ 231