diff options
Diffstat (limited to 'gl/glthread/once.h')
| -rw-r--r-- | gl/glthread/once.h | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/gl/glthread/once.h b/gl/glthread/once.h new file mode 100644 index 00000000..943bd7a2 --- /dev/null +++ b/gl/glthread/once.h | |||
| @@ -0,0 +1,272 @@ | |||
| 1 | /* Once-only initialization in multithreaded situations. | ||
| 2 | Copyright (C) 2005-2025 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 | Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h. */ | ||
| 19 | |||
| 20 | /* This file contains once-only initialization primitives for use with a given | ||
| 21 | thread library. | ||
| 22 | It does not contain primitives for creating threads or for other | ||
| 23 | synchronization primitives. | ||
| 24 | |||
| 25 | Once-only execution: | ||
| 26 | Type: gl_once_t | ||
| 27 | Initializer: gl_once_define(extern, name) | ||
| 28 | Execution: gl_once (name, initfunction); | ||
| 29 | Equivalent functions with control of error handling: | ||
| 30 | Execution: err = glthread_once (&name, initfunction); | ||
| 31 | */ | ||
| 32 | |||
| 33 | |||
| 34 | #ifndef _ONCE_H | ||
| 35 | #define _ONCE_H | ||
| 36 | |||
| 37 | /* This file uses HAVE_THREADS_H. */ | ||
| 38 | #if !_GL_CONFIG_H_INCLUDED | ||
| 39 | #error "Please include config.h first." | ||
| 40 | #endif | ||
| 41 | |||
| 42 | #include <errno.h> | ||
| 43 | #include <stdlib.h> | ||
| 44 | |||
| 45 | #if !defined c11_threads_in_use | ||
| 46 | # if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC | ||
| 47 | # define c11_threads_in_use() 1 | ||
| 48 | # elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK | ||
| 49 | # include <threads.h> | ||
| 50 | # pragma weak thrd_exit | ||
| 51 | # define c11_threads_in_use() (thrd_exit != NULL) | ||
| 52 | # else | ||
| 53 | # define c11_threads_in_use() 0 | ||
| 54 | # endif | ||
| 55 | #endif | ||
| 56 | |||
| 57 | /* ========================================================================= */ | ||
| 58 | |||
| 59 | #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS | ||
| 60 | |||
| 61 | /* Use the ISO C threads library. */ | ||
| 62 | |||
| 63 | # include <threads.h> | ||
| 64 | |||
| 65 | # ifdef __cplusplus | ||
| 66 | extern "C" { | ||
| 67 | # endif | ||
| 68 | |||
| 69 | /* -------------------------- gl_once_t datatype -------------------------- */ | ||
| 70 | |||
| 71 | typedef once_flag gl_once_t; | ||
| 72 | # define gl_once_define(STORAGECLASS, NAME) \ | ||
| 73 | STORAGECLASS once_flag NAME = ONCE_FLAG_INIT; | ||
| 74 | # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ | ||
| 75 | (call_once (ONCE_CONTROL, INITFUNCTION), 0) | ||
| 76 | |||
| 77 | # ifdef __cplusplus | ||
| 78 | } | ||
| 79 | # endif | ||
| 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 | # ifdef __cplusplus | ||
| 92 | extern "C" { | ||
| 93 | # endif | ||
| 94 | |||
| 95 | # if PTHREAD_IN_USE_DETECTION_HARD | ||
| 96 | |||
| 97 | /* The pthread_in_use() detection needs to be done at runtime. */ | ||
| 98 | # define pthread_in_use() \ | ||
| 99 | glthread_in_use () | ||
| 100 | extern int glthread_in_use (void); | ||
| 101 | |||
| 102 | # endif | ||
| 103 | |||
| 104 | # if USE_POSIX_THREADS_WEAK | ||
| 105 | |||
| 106 | /* Use weak references to the POSIX threads library. */ | ||
| 107 | |||
| 108 | /* Weak references avoid dragging in external libraries if the other parts | ||
| 109 | of the program don't use them. Here we use them, because we don't want | ||
| 110 | every program that uses libintl to depend on libpthread. This assumes | ||
| 111 | that libpthread would not be loaded after libintl; i.e. if libintl is | ||
| 112 | loaded first, by an executable that does not depend on libpthread, and | ||
| 113 | then a module is dynamically loaded that depends on libpthread, libintl | ||
| 114 | will not be multithread-safe. */ | ||
| 115 | |||
| 116 | /* The way to test at runtime whether libpthread is present is to test | ||
| 117 | whether a function pointer's value, such as &pthread_mutex_init, is | ||
| 118 | non-NULL. However, some versions of GCC have a bug through which, in | ||
| 119 | PIC mode, &foo != NULL always evaluates to true if there is a direct | ||
| 120 | call to foo(...) in the same function. To avoid this, we test the | ||
| 121 | address of a function in libpthread that we don't use. */ | ||
| 122 | |||
| 123 | # pragma weak pthread_mutex_init | ||
| 124 | # pragma weak pthread_mutex_lock | ||
| 125 | # pragma weak pthread_mutex_unlock | ||
| 126 | # pragma weak pthread_mutex_destroy | ||
| 127 | /* Work around clang bug <https://github.com/llvm/llvm-project/issues/104670> */ | ||
| 128 | # ifndef pthread_rwlock_init | ||
| 129 | # pragma weak pthread_rwlock_init | ||
| 130 | # endif | ||
| 131 | # pragma weak pthread_rwlock_rdlock | ||
| 132 | # pragma weak pthread_rwlock_wrlock | ||
| 133 | # pragma weak pthread_rwlock_unlock | ||
| 134 | # pragma weak pthread_rwlock_destroy | ||
| 135 | # pragma weak pthread_once | ||
| 136 | # pragma weak pthread_cond_init | ||
| 137 | # pragma weak pthread_cond_wait | ||
| 138 | # pragma weak pthread_cond_signal | ||
| 139 | # pragma weak pthread_cond_broadcast | ||
| 140 | # pragma weak pthread_cond_destroy | ||
| 141 | # pragma weak pthread_mutexattr_init | ||
| 142 | # pragma weak pthread_mutexattr_settype | ||
| 143 | # pragma weak pthread_mutexattr_destroy | ||
| 144 | /* Work around clang bug <https://github.com/llvm/llvm-project/issues/104670> */ | ||
| 145 | # ifndef pthread_rwlockattr_init | ||
| 146 | # pragma weak pthread_rwlockattr_init | ||
| 147 | # endif | ||
| 148 | # if __GNU_LIBRARY__ > 1 | ||
| 149 | # pragma weak pthread_rwlockattr_setkind_np | ||
| 150 | # endif | ||
| 151 | # pragma weak pthread_rwlockattr_destroy | ||
| 152 | # ifndef pthread_self | ||
| 153 | # pragma weak pthread_self | ||
| 154 | # endif | ||
| 155 | |||
| 156 | # if !PTHREAD_IN_USE_DETECTION_HARD | ||
| 157 | /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols | ||
| 158 | can be used to determine whether libpthread is in use. These are: | ||
| 159 | pthread_mutexattr_gettype | ||
| 160 | pthread_rwlockattr_destroy | ||
| 161 | pthread_rwlockattr_init | ||
| 162 | */ | ||
| 163 | # pragma weak pthread_mutexattr_gettype | ||
| 164 | # define pthread_in_use() \ | ||
| 165 | (pthread_mutexattr_gettype != NULL || c11_threads_in_use ()) | ||
| 166 | # endif | ||
| 167 | |||
| 168 | # else | ||
| 169 | |||
| 170 | # if !PTHREAD_IN_USE_DETECTION_HARD | ||
| 171 | # define pthread_in_use() 1 | ||
| 172 | # endif | ||
| 173 | |||
| 174 | # endif | ||
| 175 | |||
| 176 | /* -------------------------- gl_once_t datatype -------------------------- */ | ||
| 177 | |||
| 178 | typedef pthread_once_t gl_once_t; | ||
| 179 | # define gl_once_define(STORAGECLASS, NAME) \ | ||
| 180 | STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT; | ||
| 181 | # if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK | ||
| 182 | # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ | ||
| 183 | (pthread_in_use () \ | ||
| 184 | ? pthread_once (ONCE_CONTROL, INITFUNCTION) \ | ||
| 185 | : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) | ||
| 186 | # else | ||
| 187 | # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ | ||
| 188 | (pthread_in_use () \ | ||
| 189 | ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \ | ||
| 190 | : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) | ||
| 191 | extern int glthread_once_multithreaded (pthread_once_t *once_control, | ||
| 192 | void (*init_function) (void)); | ||
| 193 | # endif | ||
| 194 | extern int glthread_once_singlethreaded (pthread_once_t *once_control); | ||
| 195 | |||
| 196 | # ifdef __cplusplus | ||
| 197 | } | ||
| 198 | # endif | ||
| 199 | |||
| 200 | #endif | ||
| 201 | |||
| 202 | /* ========================================================================= */ | ||
| 203 | |||
| 204 | #if USE_WINDOWS_THREADS | ||
| 205 | |||
| 206 | # define WIN32_LEAN_AND_MEAN /* avoid including junk */ | ||
| 207 | # include <windows.h> | ||
| 208 | |||
| 209 | # include "windows-once.h" | ||
| 210 | |||
| 211 | # ifdef __cplusplus | ||
| 212 | extern "C" { | ||
| 213 | # endif | ||
| 214 | |||
| 215 | /* We can use CRITICAL_SECTION directly, rather than the native Windows Event, | ||
| 216 | Mutex, Semaphore types, because | ||
| 217 | - we need only to synchronize inside a single process (address space), | ||
| 218 | not inter-process locking, | ||
| 219 | - we don't need to support trylock operations. (TryEnterCriticalSection | ||
| 220 | does not work on Windows 95/98/ME. Packages that need trylock usually | ||
| 221 | define their own mutex type.) */ | ||
| 222 | |||
| 223 | /* There is no way to statically initialize a CRITICAL_SECTION. It needs | ||
| 224 | to be done lazily, once only. For this we need spinlocks. */ | ||
| 225 | |||
| 226 | /* -------------------------- gl_once_t datatype -------------------------- */ | ||
| 227 | |||
| 228 | typedef glwthread_once_t gl_once_t; | ||
| 229 | # define gl_once_define(STORAGECLASS, NAME) \ | ||
| 230 | STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT; | ||
| 231 | # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ | ||
| 232 | (glwthread_once (ONCE_CONTROL, INITFUNCTION), 0) | ||
| 233 | |||
| 234 | # ifdef __cplusplus | ||
| 235 | } | ||
| 236 | # endif | ||
| 237 | |||
| 238 | #endif | ||
| 239 | |||
| 240 | /* ========================================================================= */ | ||
| 241 | |||
| 242 | #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS) | ||
| 243 | |||
| 244 | /* Provide dummy implementation if threads are not supported. */ | ||
| 245 | |||
| 246 | /* -------------------------- gl_once_t datatype -------------------------- */ | ||
| 247 | |||
| 248 | typedef int gl_once_t; | ||
| 249 | # define gl_once_define(STORAGECLASS, NAME) \ | ||
| 250 | STORAGECLASS gl_once_t NAME = 0; | ||
| 251 | # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ | ||
| 252 | (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0) | ||
| 253 | |||
| 254 | #endif | ||
| 255 | |||
| 256 | /* ========================================================================= */ | ||
| 257 | |||
| 258 | /* Macros with built-in error handling. */ | ||
| 259 | |||
| 260 | /* -------------------------- gl_once_t datatype -------------------------- */ | ||
| 261 | |||
| 262 | #define gl_once(NAME, INITFUNCTION) \ | ||
| 263 | do \ | ||
| 264 | { \ | ||
| 265 | if (glthread_once (&NAME, INITFUNCTION)) \ | ||
| 266 | abort (); \ | ||
| 267 | } \ | ||
| 268 | while (0) | ||
| 269 | |||
| 270 | /* ========================================================================= */ | ||
| 271 | |||
| 272 | #endif /* _ONCE_H */ | ||
