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