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