1 /* Locking in multithreaded situations. 2 Copyright (C) 2005-2008, 2017-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 Lesser General Public License as published by 6 the Free Software Foundation; either version 2.1 of the License, or 7 (at your option) 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 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_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 # if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK 509 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 510 (pthread_in_use () \ 511 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \ 512 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) 513 # else 514 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 515 (pthread_in_use () \ 516 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \ 517 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) 518 extern int glthread_once_multithreaded (pthread_once_t *once_control, 519 void (*init_function) (void)); 520 # endif 521 extern int glthread_once_singlethreaded (pthread_once_t *once_control); 522 523 # ifdef __cplusplus 524 } 525 # endif 526 527 #endif 528 529 /* ========================================================================= */ 530 531 #if USE_WINDOWS_THREADS 532 533 # define WIN32_LEAN_AND_MEAN /* avoid including junk */ 534 # include <windows.h> 535 536 # include "windows-mutex.h" 537 # include "windows-rwlock.h" 538 # include "windows-recmutex.h" 539 # include "windows-once.h" 540 541 # ifdef __cplusplus 542 extern "C" { 543 # endif 544 545 /* We can use CRITICAL_SECTION directly, rather than the native Windows Event, 546 Mutex, Semaphore types, because 547 - we need only to synchronize inside a single process (address space), 548 not inter-process locking, 549 - we don't need to support trylock operations. (TryEnterCriticalSection 550 does not work on Windows 95/98/ME. Packages that need trylock usually 551 define their own mutex type.) */ 552 553 /* There is no way to statically initialize a CRITICAL_SECTION. It needs 554 to be done lazily, once only. For this we need spinlocks. */ 555 556 /* -------------------------- gl_lock_t datatype -------------------------- */ 557 558 typedef glwthread_mutex_t gl_lock_t; 559 # define gl_lock_define(STORAGECLASS, NAME) \ 560 STORAGECLASS gl_lock_t NAME; 561 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 562 STORAGECLASS gl_lock_t NAME = gl_lock_initializer; 563 # define gl_lock_initializer \ 564 GLWTHREAD_MUTEX_INIT 565 # define glthread_lock_init(LOCK) \ 566 (glwthread_mutex_init (LOCK), 0) 567 # define glthread_lock_lock(LOCK) \ 568 glwthread_mutex_lock (LOCK) 569 # define glthread_lock_unlock(LOCK) \ 570 glwthread_mutex_unlock (LOCK) 571 # define glthread_lock_destroy(LOCK) \ 572 glwthread_mutex_destroy (LOCK) 573 574 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 575 576 typedef glwthread_rwlock_t gl_rwlock_t; 577 # define gl_rwlock_define(STORAGECLASS, NAME) \ 578 STORAGECLASS gl_rwlock_t NAME; 579 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 580 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 581 # define gl_rwlock_initializer \ 582 GLWTHREAD_RWLOCK_INIT 583 # define glthread_rwlock_init(LOCK) \ 584 (glwthread_rwlock_init (LOCK), 0) 585 # define glthread_rwlock_rdlock(LOCK) \ 586 glwthread_rwlock_rdlock (LOCK) 587 # define glthread_rwlock_wrlock(LOCK) \ 588 glwthread_rwlock_wrlock (LOCK) 589 # define glthread_rwlock_unlock(LOCK) \ 590 glwthread_rwlock_unlock (LOCK) 591 # define glthread_rwlock_destroy(LOCK) \ 592 glwthread_rwlock_destroy (LOCK) 593 594 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 595 596 typedef glwthread_recmutex_t gl_recursive_lock_t; 597 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 598 STORAGECLASS gl_recursive_lock_t NAME; 599 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 600 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 601 # define gl_recursive_lock_initializer \ 602 GLWTHREAD_RECMUTEX_INIT 603 # define glthread_recursive_lock_init(LOCK) \ 604 (glwthread_recmutex_init (LOCK), 0) 605 # define glthread_recursive_lock_lock(LOCK) \ 606 glwthread_recmutex_lock (LOCK) 607 # define glthread_recursive_lock_unlock(LOCK) \ 608 glwthread_recmutex_unlock (LOCK) 609 # define glthread_recursive_lock_destroy(LOCK) \ 610 glwthread_recmutex_destroy (LOCK) 611 612 /* -------------------------- gl_once_t datatype -------------------------- */ 613 614 typedef glwthread_once_t gl_once_t; 615 # define gl_once_define(STORAGECLASS, NAME) \ 616 STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT; 617 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 618 (glwthread_once (ONCE_CONTROL, INITFUNCTION), 0) 619 620 # ifdef __cplusplus 621 } 622 # endif 623 624 #endif 625 626 /* ========================================================================= */ 627 628 #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS) 629 630 /* Provide dummy implementation if threads are not supported. */ 631 632 /* -------------------------- gl_lock_t datatype -------------------------- */ 633 634 typedef int gl_lock_t; 635 # define gl_lock_define(STORAGECLASS, NAME) 636 # define gl_lock_define_initialized(STORAGECLASS, NAME) 637 # define glthread_lock_init(NAME) 0 638 # define glthread_lock_lock(NAME) 0 639 # define glthread_lock_unlock(NAME) 0 640 # define glthread_lock_destroy(NAME) 0 641 642 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 643 644 typedef int gl_rwlock_t; 645 # define gl_rwlock_define(STORAGECLASS, NAME) 646 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) 647 # define glthread_rwlock_init(NAME) 0 648 # define glthread_rwlock_rdlock(NAME) 0 649 # define glthread_rwlock_wrlock(NAME) 0 650 # define glthread_rwlock_unlock(NAME) 0 651 # define glthread_rwlock_destroy(NAME) 0 652 653 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 654 655 typedef int gl_recursive_lock_t; 656 # define gl_recursive_lock_define(STORAGECLASS, NAME) 657 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) 658 # define glthread_recursive_lock_init(NAME) 0 659 # define glthread_recursive_lock_lock(NAME) 0 660 # define glthread_recursive_lock_unlock(NAME) 0 661 # define glthread_recursive_lock_destroy(NAME) 0 662 663 /* -------------------------- gl_once_t datatype -------------------------- */ 664 665 typedef int gl_once_t; 666 # define gl_once_define(STORAGECLASS, NAME) \ 667 STORAGECLASS gl_once_t NAME = 0; 668 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 669 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0) 670 671 #endif 672 673 /* ========================================================================= */ 674 675 /* Macros with built-in error handling. */ 676 677 /* -------------------------- gl_lock_t datatype -------------------------- */ 678 679 #define gl_lock_init(NAME) \ 680 do \ 681 { \ 682 if (glthread_lock_init (&NAME)) \ 683 abort (); \ 684 } \ 685 while (0) 686 #define gl_lock_lock(NAME) \ 687 do \ 688 { \ 689 if (glthread_lock_lock (&NAME)) \ 690 abort (); \ 691 } \ 692 while (0) 693 #define gl_lock_unlock(NAME) \ 694 do \ 695 { \ 696 if (glthread_lock_unlock (&NAME)) \ 697 abort (); \ 698 } \ 699 while (0) 700 #define gl_lock_destroy(NAME) \ 701 do \ 702 { \ 703 if (glthread_lock_destroy (&NAME)) \ 704 abort (); \ 705 } \ 706 while (0) 707 708 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 709 710 #define gl_rwlock_init(NAME) \ 711 do \ 712 { \ 713 if (glthread_rwlock_init (&NAME)) \ 714 abort (); \ 715 } \ 716 while (0) 717 #define gl_rwlock_rdlock(NAME) \ 718 do \ 719 { \ 720 if (glthread_rwlock_rdlock (&NAME)) \ 721 abort (); \ 722 } \ 723 while (0) 724 #define gl_rwlock_wrlock(NAME) \ 725 do \ 726 { \ 727 if (glthread_rwlock_wrlock (&NAME)) \ 728 abort (); \ 729 } \ 730 while (0) 731 #define gl_rwlock_unlock(NAME) \ 732 do \ 733 { \ 734 if (glthread_rwlock_unlock (&NAME)) \ 735 abort (); \ 736 } \ 737 while (0) 738 #define gl_rwlock_destroy(NAME) \ 739 do \ 740 { \ 741 if (glthread_rwlock_destroy (&NAME)) \ 742 abort (); \ 743 } \ 744 while (0) 745 746 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 747 748 #define gl_recursive_lock_init(NAME) \ 749 do \ 750 { \ 751 if (glthread_recursive_lock_init (&NAME)) \ 752 abort (); \ 753 } \ 754 while (0) 755 #define gl_recursive_lock_lock(NAME) \ 756 do \ 757 { \ 758 if (glthread_recursive_lock_lock (&NAME)) \ 759 abort (); \ 760 } \ 761 while (0) 762 #define gl_recursive_lock_unlock(NAME) \ 763 do \ 764 { \ 765 if (glthread_recursive_lock_unlock (&NAME)) \ 766 abort (); \ 767 } \ 768 while (0) 769 #define gl_recursive_lock_destroy(NAME) \ 770 do \ 771 { \ 772 if (glthread_recursive_lock_destroy (&NAME)) \ 773 abort (); \ 774 } \ 775 while (0) 776 777 /* -------------------------- gl_once_t datatype -------------------------- */ 778 779 #define gl_once(NAME, INITFUNCTION) \ 780 do \ 781 { \ 782 if (glthread_once (&NAME, INITFUNCTION)) \ 783 abort (); \ 784 } \ 785 while (0) 786 787 /* ========================================================================= */ 788 789 #endif /* _LOCK_H */ 790