1 /* Locking in multithreaded situations. 2 Copyright (C) 2005-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 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h. */ 19 20 /* This file contains locking primitives for use with a given thread library. 21 It does not contain primitives for creating threads or for other 22 synchronization primitives. 23 24 Normal (non-recursive) locks: 25 Type: gl_lock_t 26 Declaration: gl_lock_define(extern, name) 27 Initializer: gl_lock_define_initialized(, name) 28 Initialization: gl_lock_init (name); 29 Taking the lock: gl_lock_lock (name); 30 Releasing the lock: gl_lock_unlock (name); 31 De-initialization: gl_lock_destroy (name); 32 Equivalent functions with control of error handling: 33 Initialization: err = glthread_lock_init (&name); 34 Taking the lock: err = glthread_lock_lock (&name); 35 Releasing the lock: err = glthread_lock_unlock (&name); 36 De-initialization: err = glthread_lock_destroy (&name); 37 38 Read-Write (non-recursive) locks: 39 Type: gl_rwlock_t 40 Declaration: gl_rwlock_define(extern, name) 41 Initializer: gl_rwlock_define_initialized(, name) 42 Initialization: gl_rwlock_init (name); 43 Taking the lock: gl_rwlock_rdlock (name); 44 gl_rwlock_wrlock (name); 45 Releasing the lock: gl_rwlock_unlock (name); 46 De-initialization: gl_rwlock_destroy (name); 47 Equivalent functions with control of error handling: 48 Initialization: err = glthread_rwlock_init (&name); 49 Taking the lock: err = glthread_rwlock_rdlock (&name); 50 err = glthread_rwlock_wrlock (&name); 51 Releasing the lock: err = glthread_rwlock_unlock (&name); 52 De-initialization: err = glthread_rwlock_destroy (&name); 53 54 Recursive locks: 55 Type: gl_recursive_lock_t 56 Declaration: gl_recursive_lock_define(extern, name) 57 Initializer: gl_recursive_lock_define_initialized(, name) 58 Initialization: gl_recursive_lock_init (name); 59 Taking the lock: gl_recursive_lock_lock (name); 60 Releasing the lock: gl_recursive_lock_unlock (name); 61 De-initialization: gl_recursive_lock_destroy (name); 62 Equivalent functions with control of error handling: 63 Initialization: err = glthread_recursive_lock_init (&name); 64 Taking the lock: err = glthread_recursive_lock_lock (&name); 65 Releasing the lock: err = glthread_recursive_lock_unlock (&name); 66 De-initialization: err = glthread_recursive_lock_destroy (&name); 67 68 Once-only execution: 69 Type: gl_once_t 70 Initializer: gl_once_define(extern, name) 71 Execution: gl_once (name, initfunction); 72 Equivalent functions with control of error handling: 73 Execution: err = glthread_once (&name, initfunction); 74 */ 75 76 77 #ifndef _LOCK_H 78 #define _LOCK_H 79 80 #include <errno.h> 81 #include <stdlib.h> 82 83 #if !defined c11_threads_in_use 84 # if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC 85 # define c11_threads_in_use() 1 86 # elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK 87 # include <threads.h> 88 # pragma weak thrd_exit 89 # define c11_threads_in_use() (thrd_exit != NULL) 90 # else 91 # define c11_threads_in_use() 0 92 # endif 93 #endif 94 95 /* ========================================================================= */ 96 97 #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS 98 99 /* Use the ISO C threads library. */ 100 101 # include <threads.h> 102 103 # ifdef __cplusplus 104 extern "C" { 105 # endif 106 107 /* -------------------------- gl_lock_t datatype -------------------------- */ 108 109 typedef struct 110 { 111 int volatile init_needed; 112 once_flag init_once; 113 void (*init_func) (void); 114 mtx_t mutex; 115 } 116 gl_lock_t; 117 # define gl_lock_define(STORAGECLASS, NAME) \ 118 STORAGECLASS gl_lock_t NAME; 119 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 120 static void _atomic_init_##NAME (void); \ 121 STORAGECLASS gl_lock_t NAME = \ 122 { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \ 123 static void _atomic_init_##NAME (void) \ 124 { \ 125 if (glthread_lock_init (&(NAME))) \ 126 abort (); \ 127 } 128 extern int glthread_lock_init (gl_lock_t *lock); 129 extern int glthread_lock_lock (gl_lock_t *lock); 130 extern int glthread_lock_unlock (gl_lock_t *lock); 131 extern int glthread_lock_destroy (gl_lock_t *lock); 132 133 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 134 135 typedef struct 136 { 137 int volatile init_needed; 138 once_flag init_once; 139 void (*init_func) (void); 140 mtx_t lock; /* protects the remaining fields */ 141 cnd_t waiting_readers; /* waiting readers */ 142 cnd_t waiting_writers; /* waiting writers */ 143 unsigned int waiting_writers_count; /* number of waiting writers */ 144 int runcount; /* number of readers running, or -1 when a writer runs */ 145 } 146 gl_rwlock_t; 147 # define gl_rwlock_define(STORAGECLASS, NAME) \ 148 STORAGECLASS gl_rwlock_t NAME; 149 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 150 static void _atomic_init_##NAME (void); \ 151 STORAGECLASS gl_rwlock_t NAME = \ 152 { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \ 153 static void _atomic_init_##NAME (void) \ 154 { \ 155 if (glthread_rwlock_init (&(NAME))) \ 156 abort (); \ 157 } 158 extern int glthread_rwlock_init (gl_rwlock_t *lock); 159 extern int glthread_rwlock_rdlock (gl_rwlock_t *lock); 160 extern int glthread_rwlock_wrlock (gl_rwlock_t *lock); 161 extern int glthread_rwlock_unlock (gl_rwlock_t *lock); 162 extern int glthread_rwlock_destroy (gl_rwlock_t *lock); 163 164 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 165 166 typedef struct 167 { 168 int volatile init_needed; 169 once_flag init_once; 170 void (*init_func) (void); 171 mtx_t mutex; 172 } 173 gl_recursive_lock_t; 174 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 175 STORAGECLASS gl_recursive_lock_t NAME; 176 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 177 static void _atomic_init_##NAME (void); \ 178 STORAGECLASS gl_recursive_lock_t NAME = \ 179 { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \ 180 static void _atomic_init_##NAME (void) \ 181 { \ 182 if (glthread_recursive_lock_init (&(NAME))) \ 183 abort (); \ 184 } 185 extern int glthread_recursive_lock_init (gl_recursive_lock_t *lock); 186 extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock); 187 extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock); 188 extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); 189 190 /* -------------------------- gl_once_t datatype -------------------------- */ 191 192 typedef once_flag gl_once_t; 193 # define gl_once_define(STORAGECLASS, NAME) \ 194 STORAGECLASS once_flag NAME = ONCE_FLAG_INIT; 195 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 196 (call_once (ONCE_CONTROL, INITFUNCTION), 0) 197 198 # ifdef __cplusplus 199 } 200 # endif 201 202 #endif 203 204 /* ========================================================================= */ 205 206 #if USE_POSIX_THREADS 207 208 /* Use the POSIX threads library. */ 209 210 # include <pthread.h> 211 212 # ifdef __cplusplus 213 extern "C" { 214 # endif 215 216 # if PTHREAD_IN_USE_DETECTION_HARD 217 218 /* The pthread_in_use() detection needs to be done at runtime. */ 219 # define pthread_in_use() \ 220 glthread_in_use () 221 extern int glthread_in_use (void); 222 223 # endif 224 225 # if USE_POSIX_THREADS_WEAK 226 227 /* Use weak references to the POSIX threads library. */ 228 229 /* Weak references avoid dragging in external libraries if the other parts 230 of the program don't use them. Here we use them, because we don't want 231 every program that uses libintl to depend on libpthread. This assumes 232 that libpthread would not be loaded after libintl; i.e. if libintl is 233 loaded first, by an executable that does not depend on libpthread, and 234 then a module is dynamically loaded that depends on libpthread, libintl 235 will not be multithread-safe. */ 236 237 /* The way to test at runtime whether libpthread is present is to test 238 whether a function pointer's value, such as &pthread_mutex_init, is 239 non-NULL. However, some versions of GCC have a bug through which, in 240 PIC mode, &foo != NULL always evaluates to true if there is a direct 241 call to foo(...) in the same function. To avoid this, we test the 242 address of a function in libpthread that we don't use. */ 243 244 # pragma weak pthread_mutex_init 245 # pragma weak pthread_mutex_lock 246 # pragma weak pthread_mutex_unlock 247 # pragma weak pthread_mutex_destroy 248 # pragma weak pthread_rwlock_init 249 # pragma weak pthread_rwlock_rdlock 250 # pragma weak pthread_rwlock_wrlock 251 # pragma weak pthread_rwlock_unlock 252 # pragma weak pthread_rwlock_destroy 253 # pragma weak pthread_once 254 # pragma weak pthread_cond_init 255 # pragma weak pthread_cond_wait 256 # pragma weak pthread_cond_signal 257 # pragma weak pthread_cond_broadcast 258 # pragma weak pthread_cond_destroy 259 # pragma weak pthread_mutexattr_init 260 # pragma weak pthread_mutexattr_settype 261 # pragma weak pthread_mutexattr_destroy 262 # pragma weak pthread_rwlockattr_init 263 # if __GNU_LIBRARY__ > 1 264 # pragma weak pthread_rwlockattr_setkind_np 265 # endif 266 # pragma weak pthread_rwlockattr_destroy 267 # ifndef pthread_self 268 # pragma weak pthread_self 269 # endif 270 271 # if !PTHREAD_IN_USE_DETECTION_HARD 272 /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols 273 can be used to determine whether libpthread is in use. These are: 274 pthread_mutexattr_gettype 275 pthread_rwlockattr_destroy 276 pthread_rwlockattr_init 277 */ 278 # pragma weak pthread_mutexattr_gettype 279 # define pthread_in_use() \ 280 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ()) 281 # endif 282 283 # else 284 285 # if !PTHREAD_IN_USE_DETECTION_HARD 286 # define pthread_in_use() 1 287 # endif 288 289 # endif 290 291 /* -------------------------- gl_lock_t datatype -------------------------- */ 292 293 typedef pthread_mutex_t gl_lock_t; 294 # define gl_lock_define(STORAGECLASS, NAME) \ 295 STORAGECLASS pthread_mutex_t NAME; 296 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 297 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer; 298 # define gl_lock_initializer \ 299 PTHREAD_MUTEX_INITIALIZER 300 # define glthread_lock_init(LOCK) \ 301 (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0) 302 # define glthread_lock_lock(LOCK) \ 303 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0) 304 # define glthread_lock_unlock(LOCK) \ 305 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0) 306 # define glthread_lock_destroy(LOCK) \ 307 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0) 308 309 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 310 311 # if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1))) 312 313 # if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP 314 315 typedef pthread_rwlock_t gl_rwlock_t; 316 # define gl_rwlock_define(STORAGECLASS, NAME) \ 317 STORAGECLASS pthread_rwlock_t NAME; 318 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 319 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer; 320 # if HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER 321 # if defined PTHREAD_RWLOCK_INITIALIZER 322 # define gl_rwlock_initializer \ 323 PTHREAD_RWLOCK_INITIALIZER 324 # else 325 # define gl_rwlock_initializer \ 326 PTHREAD_RWLOCK_INITIALIZER_NP 327 # endif 328 # define glthread_rwlock_init(LOCK) \ 329 (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0) 330 # else /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */ 331 # define gl_rwlock_initializer \ 332 PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP 333 # define glthread_rwlock_init(LOCK) \ 334 (pthread_in_use () ? glthread_rwlock_init_for_glibc (LOCK) : 0) 335 extern int glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock); 336 # endif 337 # define glthread_rwlock_rdlock(LOCK) \ 338 (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0) 339 # define glthread_rwlock_wrlock(LOCK) \ 340 (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0) 341 # define glthread_rwlock_unlock(LOCK) \ 342 (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0) 343 # define glthread_rwlock_destroy(LOCK) \ 344 (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0) 345 346 # else 347 348 typedef struct 349 { 350 int initialized; 351 pthread_mutex_t guard; /* protects the initialization */ 352 pthread_rwlock_t rwlock; /* read-write lock */ 353 } 354 gl_rwlock_t; 355 # define gl_rwlock_define(STORAGECLASS, NAME) \ 356 STORAGECLASS gl_rwlock_t NAME; 357 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 358 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 359 # define gl_rwlock_initializer \ 360 { 0, PTHREAD_MUTEX_INITIALIZER } 361 # define glthread_rwlock_init(LOCK) \ 362 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0) 363 # define glthread_rwlock_rdlock(LOCK) \ 364 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0) 365 # define glthread_rwlock_wrlock(LOCK) \ 366 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0) 367 # define glthread_rwlock_unlock(LOCK) \ 368 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0) 369 # define glthread_rwlock_destroy(LOCK) \ 370 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0) 371 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock); 372 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock); 373 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock); 374 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock); 375 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock); 376 377 # endif 378 379 # else 380 381 typedef struct 382 { 383 pthread_mutex_t lock; /* protects the remaining fields */ 384 pthread_cond_t waiting_readers; /* waiting readers */ 385 pthread_cond_t waiting_writers; /* waiting writers */ 386 unsigned int waiting_writers_count; /* number of waiting writers */ 387 int runcount; /* number of readers running, or -1 when a writer runs */ 388 } 389 gl_rwlock_t; 390 # define gl_rwlock_define(STORAGECLASS, NAME) \ 391 STORAGECLASS gl_rwlock_t NAME; 392 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 393 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 394 # define gl_rwlock_initializer \ 395 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 } 396 # define glthread_rwlock_init(LOCK) \ 397 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0) 398 # define glthread_rwlock_rdlock(LOCK) \ 399 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0) 400 # define glthread_rwlock_wrlock(LOCK) \ 401 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0) 402 # define glthread_rwlock_unlock(LOCK) \ 403 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0) 404 # define glthread_rwlock_destroy(LOCK) \ 405 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0) 406 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock); 407 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock); 408 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock); 409 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock); 410 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock); 411 412 # endif 413 414 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 415 416 # if HAVE_PTHREAD_MUTEX_RECURSIVE 417 418 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 419 420 typedef pthread_mutex_t gl_recursive_lock_t; 421 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 422 STORAGECLASS pthread_mutex_t NAME; 423 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 424 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer; 425 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER 426 # define gl_recursive_lock_initializer \ 427 PTHREAD_RECURSIVE_MUTEX_INITIALIZER 428 # else 429 # define gl_recursive_lock_initializer \ 430 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 431 # endif 432 # define glthread_recursive_lock_init(LOCK) \ 433 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 434 # define glthread_recursive_lock_lock(LOCK) \ 435 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0) 436 # define glthread_recursive_lock_unlock(LOCK) \ 437 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0) 438 # define glthread_recursive_lock_destroy(LOCK) \ 439 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0) 440 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 441 442 # else 443 444 typedef struct 445 { 446 pthread_mutex_t recmutex; /* recursive mutex */ 447 pthread_mutex_t guard; /* protects the initialization */ 448 int initialized; 449 } 450 gl_recursive_lock_t; 451 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 452 STORAGECLASS gl_recursive_lock_t NAME; 453 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 454 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 455 # define gl_recursive_lock_initializer \ 456 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 } 457 # define glthread_recursive_lock_init(LOCK) \ 458 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 459 # define glthread_recursive_lock_lock(LOCK) \ 460 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0) 461 # define glthread_recursive_lock_unlock(LOCK) \ 462 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0) 463 # define glthread_recursive_lock_destroy(LOCK) \ 464 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0) 465 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 466 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock); 467 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock); 468 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock); 469 470 # endif 471 472 # else 473 474 /* Old versions of POSIX threads on Solaris did not have recursive locks. 475 We have to implement them ourselves. */ 476 477 typedef struct 478 { 479 pthread_mutex_t mutex; 480 pthread_t owner; 481 unsigned long depth; 482 } 483 gl_recursive_lock_t; 484 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 485 STORAGECLASS gl_recursive_lock_t NAME; 486 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 487 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 488 # define gl_recursive_lock_initializer \ 489 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 } 490 # define glthread_recursive_lock_init(LOCK) \ 491 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 492 # define glthread_recursive_lock_lock(LOCK) \ 493 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0) 494 # define glthread_recursive_lock_unlock(LOCK) \ 495 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0) 496 # define glthread_recursive_lock_destroy(LOCK) \ 497 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0) 498 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 499 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock); 500 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock); 501 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock); 502 503 # endif 504 505 /* -------------------------- gl_once_t datatype -------------------------- */ 506 507 typedef pthread_once_t gl_once_t; 508 # define gl_once_define(STORAGECLASS, NAME) \ 509 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT; 510 # if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK 511 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 512 (pthread_in_use () \ 513 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \ 514 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) 515 # else 516 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 517 (pthread_in_use () \ 518 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \ 519 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) 520 extern int glthread_once_multithreaded (pthread_once_t *once_control, 521 void (*init_function) (void)); 522 # endif 523 extern int glthread_once_singlethreaded (pthread_once_t *once_control); 524 525 # ifdef __cplusplus 526 } 527 # endif 528 529 #endif 530 531 /* ========================================================================= */ 532 533 #if USE_WINDOWS_THREADS 534 535 # define WIN32_LEAN_AND_MEAN /* avoid including junk */ 536 # include <windows.h> 537 538 # include "windows-mutex.h" 539 # include "windows-rwlock.h" 540 # include "windows-recmutex.h" 541 # include "windows-once.h" 542 543 # ifdef __cplusplus 544 extern "C" { 545 # endif 546 547 /* We can use CRITICAL_SECTION directly, rather than the native Windows Event, 548 Mutex, Semaphore types, because 549 - we need only to synchronize inside a single process (address space), 550 not inter-process locking, 551 - we don't need to support trylock operations. (TryEnterCriticalSection 552 does not work on Windows 95/98/ME. Packages that need trylock usually 553 define their own mutex type.) */ 554 555 /* There is no way to statically initialize a CRITICAL_SECTION. It needs 556 to be done lazily, once only. For this we need spinlocks. */ 557 558 /* -------------------------- gl_lock_t datatype -------------------------- */ 559 560 typedef glwthread_mutex_t gl_lock_t; 561 # define gl_lock_define(STORAGECLASS, NAME) \ 562 STORAGECLASS gl_lock_t NAME; 563 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 564 STORAGECLASS gl_lock_t NAME = gl_lock_initializer; 565 # define gl_lock_initializer \ 566 GLWTHREAD_MUTEX_INIT 567 # define glthread_lock_init(LOCK) \ 568 (glwthread_mutex_init (LOCK), 0) 569 # define glthread_lock_lock(LOCK) \ 570 glwthread_mutex_lock (LOCK) 571 # define glthread_lock_unlock(LOCK) \ 572 glwthread_mutex_unlock (LOCK) 573 # define glthread_lock_destroy(LOCK) \ 574 glwthread_mutex_destroy (LOCK) 575 576 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 577 578 typedef glwthread_rwlock_t gl_rwlock_t; 579 # define gl_rwlock_define(STORAGECLASS, NAME) \ 580 STORAGECLASS gl_rwlock_t NAME; 581 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 582 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 583 # define gl_rwlock_initializer \ 584 GLWTHREAD_RWLOCK_INIT 585 # define glthread_rwlock_init(LOCK) \ 586 (glwthread_rwlock_init (LOCK), 0) 587 # define glthread_rwlock_rdlock(LOCK) \ 588 glwthread_rwlock_rdlock (LOCK) 589 # define glthread_rwlock_wrlock(LOCK) \ 590 glwthread_rwlock_wrlock (LOCK) 591 # define glthread_rwlock_unlock(LOCK) \ 592 glwthread_rwlock_unlock (LOCK) 593 # define glthread_rwlock_destroy(LOCK) \ 594 glwthread_rwlock_destroy (LOCK) 595 596 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 597 598 typedef glwthread_recmutex_t gl_recursive_lock_t; 599 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 600 STORAGECLASS gl_recursive_lock_t NAME; 601 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 602 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 603 # define gl_recursive_lock_initializer \ 604 GLWTHREAD_RECMUTEX_INIT 605 # define glthread_recursive_lock_init(LOCK) \ 606 (glwthread_recmutex_init (LOCK), 0) 607 # define glthread_recursive_lock_lock(LOCK) \ 608 glwthread_recmutex_lock (LOCK) 609 # define glthread_recursive_lock_unlock(LOCK) \ 610 glwthread_recmutex_unlock (LOCK) 611 # define glthread_recursive_lock_destroy(LOCK) \ 612 glwthread_recmutex_destroy (LOCK) 613 614 /* -------------------------- gl_once_t datatype -------------------------- */ 615 616 typedef glwthread_once_t gl_once_t; 617 # define gl_once_define(STORAGECLASS, NAME) \ 618 STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT; 619 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 620 (glwthread_once (ONCE_CONTROL, INITFUNCTION), 0) 621 622 # ifdef __cplusplus 623 } 624 # endif 625 626 #endif 627 628 /* ========================================================================= */ 629 630 #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS) 631 632 /* Provide dummy implementation if threads are not supported. */ 633 634 /* -------------------------- gl_lock_t datatype -------------------------- */ 635 636 typedef int gl_lock_t; 637 # define gl_lock_define(STORAGECLASS, NAME) 638 # define gl_lock_define_initialized(STORAGECLASS, NAME) 639 # define glthread_lock_init(NAME) 0 640 # define glthread_lock_lock(NAME) 0 641 # define glthread_lock_unlock(NAME) 0 642 # define glthread_lock_destroy(NAME) 0 643 644 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 645 646 typedef int gl_rwlock_t; 647 # define gl_rwlock_define(STORAGECLASS, NAME) 648 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) 649 # define glthread_rwlock_init(NAME) 0 650 # define glthread_rwlock_rdlock(NAME) 0 651 # define glthread_rwlock_wrlock(NAME) 0 652 # define glthread_rwlock_unlock(NAME) 0 653 # define glthread_rwlock_destroy(NAME) 0 654 655 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 656 657 typedef int gl_recursive_lock_t; 658 # define gl_recursive_lock_define(STORAGECLASS, NAME) 659 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) 660 # define glthread_recursive_lock_init(NAME) 0 661 # define glthread_recursive_lock_lock(NAME) 0 662 # define glthread_recursive_lock_unlock(NAME) 0 663 # define glthread_recursive_lock_destroy(NAME) 0 664 665 /* -------------------------- gl_once_t datatype -------------------------- */ 666 667 typedef int gl_once_t; 668 # define gl_once_define(STORAGECLASS, NAME) \ 669 STORAGECLASS gl_once_t NAME = 0; 670 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 671 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0) 672 673 #endif 674 675 /* ========================================================================= */ 676 677 /* Macros with built-in error handling. */ 678 679 /* -------------------------- gl_lock_t datatype -------------------------- */ 680 681 #define gl_lock_init(NAME) \ 682 do \ 683 { \ 684 if (glthread_lock_init (&NAME)) \ 685 abort (); \ 686 } \ 687 while (0) 688 #define gl_lock_lock(NAME) \ 689 do \ 690 { \ 691 if (glthread_lock_lock (&NAME)) \ 692 abort (); \ 693 } \ 694 while (0) 695 #define gl_lock_unlock(NAME) \ 696 do \ 697 { \ 698 if (glthread_lock_unlock (&NAME)) \ 699 abort (); \ 700 } \ 701 while (0) 702 #define gl_lock_destroy(NAME) \ 703 do \ 704 { \ 705 if (glthread_lock_destroy (&NAME)) \ 706 abort (); \ 707 } \ 708 while (0) 709 710 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 711 712 #define gl_rwlock_init(NAME) \ 713 do \ 714 { \ 715 if (glthread_rwlock_init (&NAME)) \ 716 abort (); \ 717 } \ 718 while (0) 719 #define gl_rwlock_rdlock(NAME) \ 720 do \ 721 { \ 722 if (glthread_rwlock_rdlock (&NAME)) \ 723 abort (); \ 724 } \ 725 while (0) 726 #define gl_rwlock_wrlock(NAME) \ 727 do \ 728 { \ 729 if (glthread_rwlock_wrlock (&NAME)) \ 730 abort (); \ 731 } \ 732 while (0) 733 #define gl_rwlock_unlock(NAME) \ 734 do \ 735 { \ 736 if (glthread_rwlock_unlock (&NAME)) \ 737 abort (); \ 738 } \ 739 while (0) 740 #define gl_rwlock_destroy(NAME) \ 741 do \ 742 { \ 743 if (glthread_rwlock_destroy (&NAME)) \ 744 abort (); \ 745 } \ 746 while (0) 747 748 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 749 750 #define gl_recursive_lock_init(NAME) \ 751 do \ 752 { \ 753 if (glthread_recursive_lock_init (&NAME)) \ 754 abort (); \ 755 } \ 756 while (0) 757 #define gl_recursive_lock_lock(NAME) \ 758 do \ 759 { \ 760 if (glthread_recursive_lock_lock (&NAME)) \ 761 abort (); \ 762 } \ 763 while (0) 764 #define gl_recursive_lock_unlock(NAME) \ 765 do \ 766 { \ 767 if (glthread_recursive_lock_unlock (&NAME)) \ 768 abort (); \ 769 } \ 770 while (0) 771 #define gl_recursive_lock_destroy(NAME) \ 772 do \ 773 { \ 774 if (glthread_recursive_lock_destroy (&NAME)) \ 775 abort (); \ 776 } \ 777 while (0) 778 779 /* -------------------------- gl_once_t datatype -------------------------- */ 780 781 #define gl_once(NAME, INITFUNCTION) \ 782 do \ 783 { \ 784 if (glthread_once (&NAME, INITFUNCTION)) \ 785 abort (); \ 786 } \ 787 while (0) 788 789 /* ========================================================================= */ 790 791 #endif /* _LOCK_H */ 792