1 /* Locking in multithreaded situations. 2 Copyright (C) 2005-2018 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-solaris.h, 19 gthr-win32.h. */ 20 21 /* This file contains locking primitives for use with a given thread library. 22 It does not contain primitives for creating threads or for other 23 synchronization primitives. 24 25 Normal (non-recursive) locks: 26 Type: gl_lock_t 27 Declaration: gl_lock_define(extern, name) 28 Initializer: gl_lock_define_initialized(, name) 29 Initialization: gl_lock_init (name); 30 Taking the lock: gl_lock_lock (name); 31 Releasing the lock: gl_lock_unlock (name); 32 De-initialization: gl_lock_destroy (name); 33 Equivalent functions with control of error handling: 34 Initialization: err = glthread_lock_init (&name); 35 Taking the lock: err = glthread_lock_lock (&name); 36 Releasing the lock: err = glthread_lock_unlock (&name); 37 De-initialization: err = glthread_lock_destroy (&name); 38 39 Read-Write (non-recursive) locks: 40 Type: gl_rwlock_t 41 Declaration: gl_rwlock_define(extern, name) 42 Initializer: gl_rwlock_define_initialized(, name) 43 Initialization: gl_rwlock_init (name); 44 Taking the lock: gl_rwlock_rdlock (name); 45 gl_rwlock_wrlock (name); 46 Releasing the lock: gl_rwlock_unlock (name); 47 De-initialization: gl_rwlock_destroy (name); 48 Equivalent functions with control of error handling: 49 Initialization: err = glthread_rwlock_init (&name); 50 Taking the lock: err = glthread_rwlock_rdlock (&name); 51 err = glthread_rwlock_wrlock (&name); 52 Releasing the lock: err = glthread_rwlock_unlock (&name); 53 De-initialization: err = glthread_rwlock_destroy (&name); 54 55 Recursive locks: 56 Type: gl_recursive_lock_t 57 Declaration: gl_recursive_lock_define(extern, name) 58 Initializer: gl_recursive_lock_define_initialized(, name) 59 Initialization: gl_recursive_lock_init (name); 60 Taking the lock: gl_recursive_lock_lock (name); 61 Releasing the lock: gl_recursive_lock_unlock (name); 62 De-initialization: gl_recursive_lock_destroy (name); 63 Equivalent functions with control of error handling: 64 Initialization: err = glthread_recursive_lock_init (&name); 65 Taking the lock: err = glthread_recursive_lock_lock (&name); 66 Releasing the lock: err = glthread_recursive_lock_unlock (&name); 67 De-initialization: err = glthread_recursive_lock_destroy (&name); 68 69 Once-only execution: 70 Type: gl_once_t 71 Initializer: gl_once_define(extern, name) 72 Execution: gl_once (name, initfunction); 73 Equivalent functions with control of error handling: 74 Execution: err = glthread_once (&name, initfunction); 75 */ 76 77 78 #ifndef _LOCK_H 79 #define _LOCK_H 80 81 #include <errno.h> 82 #include <stdlib.h> 83 84 /* ========================================================================= */ 85 86 #if USE_POSIX_THREADS 87 88 /* Use the POSIX threads library. */ 89 90 # include <pthread.h> 91 92 # ifdef __cplusplus 93 extern "C" { 94 # endif 95 96 # if PTHREAD_IN_USE_DETECTION_HARD 97 98 /* The pthread_in_use() detection needs to be done at runtime. */ 99 # define pthread_in_use() \ 100 glthread_in_use () 101 extern int glthread_in_use (void); 102 103 # endif 104 105 # if USE_POSIX_THREADS_WEAK 106 107 /* Use weak references to the POSIX threads library. */ 108 109 /* Weak references avoid dragging in external libraries if the other parts 110 of the program don't use them. Here we use them, because we don't want 111 every program that uses libintl to depend on libpthread. This assumes 112 that libpthread would not be loaded after libintl; i.e. if libintl is 113 loaded first, by an executable that does not depend on libpthread, and 114 then a module is dynamically loaded that depends on libpthread, libintl 115 will not be multithread-safe. */ 116 117 /* The way to test at runtime whether libpthread is present is to test 118 whether a function pointer's value, such as &pthread_mutex_init, is 119 non-NULL. However, some versions of GCC have a bug through which, in 120 PIC mode, &foo != NULL always evaluates to true if there is a direct 121 call to foo(...) in the same function. To avoid this, we test the 122 address of a function in libpthread that we don't use. */ 123 124 # pragma weak pthread_mutex_init 125 # pragma weak pthread_mutex_lock 126 # pragma weak pthread_mutex_unlock 127 # pragma weak pthread_mutex_destroy 128 # pragma weak pthread_rwlock_init 129 # pragma weak pthread_rwlock_rdlock 130 # pragma weak pthread_rwlock_wrlock 131 # pragma weak pthread_rwlock_unlock 132 # pragma weak pthread_rwlock_destroy 133 # pragma weak pthread_once 134 # pragma weak pthread_cond_init 135 # pragma weak pthread_cond_wait 136 # pragma weak pthread_cond_signal 137 # pragma weak pthread_cond_broadcast 138 # pragma weak pthread_cond_destroy 139 # pragma weak pthread_mutexattr_init 140 # pragma weak pthread_mutexattr_settype 141 # pragma weak pthread_mutexattr_destroy 142 # pragma weak pthread_rwlockattr_init 143 # if __GNU_LIBRARY__ > 1 144 # pragma weak pthread_rwlockattr_setkind_np 145 # endif 146 # pragma weak pthread_rwlockattr_destroy 147 # ifndef pthread_self 148 # pragma weak pthread_self 149 # endif 150 151 # if !PTHREAD_IN_USE_DETECTION_HARD 152 # pragma weak pthread_cancel 153 # define pthread_in_use() (pthread_cancel != NULL) 154 # endif 155 156 # else 157 158 # if !PTHREAD_IN_USE_DETECTION_HARD 159 # define pthread_in_use() 1 160 # endif 161 162 # endif 163 164 /* -------------------------- gl_lock_t datatype -------------------------- */ 165 166 typedef pthread_mutex_t gl_lock_t; 167 # define gl_lock_define(STORAGECLASS, NAME) \ 168 STORAGECLASS pthread_mutex_t NAME; 169 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 170 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer; 171 # define gl_lock_initializer \ 172 PTHREAD_MUTEX_INITIALIZER 173 # define glthread_lock_init(LOCK) \ 174 (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0) 175 # define glthread_lock_lock(LOCK) \ 176 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0) 177 # define glthread_lock_unlock(LOCK) \ 178 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0) 179 # define glthread_lock_destroy(LOCK) \ 180 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0) 181 182 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 183 184 # if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1))) 185 186 # ifdef PTHREAD_RWLOCK_INITIALIZER 187 188 typedef pthread_rwlock_t gl_rwlock_t; 189 # define gl_rwlock_define(STORAGECLASS, NAME) \ 190 STORAGECLASS pthread_rwlock_t NAME; 191 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 192 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer; 193 # if HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER 194 # define gl_rwlock_initializer \ 195 PTHREAD_RWLOCK_INITIALIZER 196 # define glthread_rwlock_init(LOCK) \ 197 (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0) 198 # else /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */ 199 # define gl_rwlock_initializer \ 200 PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP 201 # define glthread_rwlock_init(LOCK) \ 202 (pthread_in_use () ? glthread_rwlock_init_for_glibc (LOCK) : 0) 203 extern int glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock); 204 # endif 205 # define glthread_rwlock_rdlock(LOCK) \ 206 (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0) 207 # define glthread_rwlock_wrlock(LOCK) \ 208 (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0) 209 # define glthread_rwlock_unlock(LOCK) \ 210 (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0) 211 # define glthread_rwlock_destroy(LOCK) \ 212 (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0) 213 214 # else 215 216 typedef struct 217 { 218 int initialized; 219 pthread_mutex_t guard; /* protects the initialization */ 220 pthread_rwlock_t rwlock; /* read-write lock */ 221 } 222 gl_rwlock_t; 223 # define gl_rwlock_define(STORAGECLASS, NAME) \ 224 STORAGECLASS gl_rwlock_t NAME; 225 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 226 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 227 # define gl_rwlock_initializer \ 228 { 0, PTHREAD_MUTEX_INITIALIZER } 229 # define glthread_rwlock_init(LOCK) \ 230 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0) 231 # define glthread_rwlock_rdlock(LOCK) \ 232 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0) 233 # define glthread_rwlock_wrlock(LOCK) \ 234 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0) 235 # define glthread_rwlock_unlock(LOCK) \ 236 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0) 237 # define glthread_rwlock_destroy(LOCK) \ 238 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0) 239 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock); 240 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock); 241 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock); 242 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock); 243 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock); 244 245 # endif 246 247 # else 248 249 typedef struct 250 { 251 pthread_mutex_t lock; /* protects the remaining fields */ 252 pthread_cond_t waiting_readers; /* waiting readers */ 253 pthread_cond_t waiting_writers; /* waiting writers */ 254 unsigned int waiting_writers_count; /* number of waiting writers */ 255 int runcount; /* number of readers running, or -1 when a writer runs */ 256 } 257 gl_rwlock_t; 258 # define gl_rwlock_define(STORAGECLASS, NAME) \ 259 STORAGECLASS gl_rwlock_t NAME; 260 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 261 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 262 # define gl_rwlock_initializer \ 263 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 } 264 # define glthread_rwlock_init(LOCK) \ 265 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0) 266 # define glthread_rwlock_rdlock(LOCK) \ 267 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0) 268 # define glthread_rwlock_wrlock(LOCK) \ 269 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0) 270 # define glthread_rwlock_unlock(LOCK) \ 271 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0) 272 # define glthread_rwlock_destroy(LOCK) \ 273 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0) 274 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock); 275 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock); 276 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock); 277 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock); 278 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock); 279 280 # endif 281 282 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 283 284 # if HAVE_PTHREAD_MUTEX_RECURSIVE 285 286 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 287 288 typedef pthread_mutex_t gl_recursive_lock_t; 289 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 290 STORAGECLASS pthread_mutex_t NAME; 291 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 292 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer; 293 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER 294 # define gl_recursive_lock_initializer \ 295 PTHREAD_RECURSIVE_MUTEX_INITIALIZER 296 # else 297 # define gl_recursive_lock_initializer \ 298 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 299 # endif 300 # define glthread_recursive_lock_init(LOCK) \ 301 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 302 # define glthread_recursive_lock_lock(LOCK) \ 303 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0) 304 # define glthread_recursive_lock_unlock(LOCK) \ 305 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0) 306 # define glthread_recursive_lock_destroy(LOCK) \ 307 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0) 308 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 309 310 # else 311 312 typedef struct 313 { 314 pthread_mutex_t recmutex; /* recursive mutex */ 315 pthread_mutex_t guard; /* protects the initialization */ 316 int initialized; 317 } 318 gl_recursive_lock_t; 319 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 320 STORAGECLASS gl_recursive_lock_t NAME; 321 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 322 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 323 # define gl_recursive_lock_initializer \ 324 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 } 325 # define glthread_recursive_lock_init(LOCK) \ 326 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 327 # define glthread_recursive_lock_lock(LOCK) \ 328 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0) 329 # define glthread_recursive_lock_unlock(LOCK) \ 330 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0) 331 # define glthread_recursive_lock_destroy(LOCK) \ 332 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0) 333 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 334 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock); 335 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock); 336 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock); 337 338 # endif 339 340 # else 341 342 /* Old versions of POSIX threads on Solaris did not have recursive locks. 343 We have to implement them ourselves. */ 344 345 typedef struct 346 { 347 pthread_mutex_t mutex; 348 pthread_t owner; 349 unsigned long depth; 350 } 351 gl_recursive_lock_t; 352 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 353 STORAGECLASS gl_recursive_lock_t NAME; 354 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 355 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 356 # define gl_recursive_lock_initializer \ 357 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 } 358 # define glthread_recursive_lock_init(LOCK) \ 359 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 360 # define glthread_recursive_lock_lock(LOCK) \ 361 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0) 362 # define glthread_recursive_lock_unlock(LOCK) \ 363 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0) 364 # define glthread_recursive_lock_destroy(LOCK) \ 365 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0) 366 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 367 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock); 368 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock); 369 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock); 370 371 # endif 372 373 /* -------------------------- gl_once_t datatype -------------------------- */ 374 375 typedef pthread_once_t gl_once_t; 376 # define gl_once_define(STORAGECLASS, NAME) \ 377 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT; 378 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 379 (pthread_in_use () \ 380 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \ 381 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) 382 extern int glthread_once_singlethreaded (pthread_once_t *once_control); 383 384 # ifdef __cplusplus 385 } 386 # endif 387 388 #endif 389 390 /* ========================================================================= */ 391 392 #if USE_PTH_THREADS 393 394 /* Use the GNU Pth threads library. */ 395 396 # include <pth.h> 397 398 # ifdef __cplusplus 399 extern "C" { 400 # endif 401 402 # if USE_PTH_THREADS_WEAK 403 404 /* Use weak references to the GNU Pth threads library. */ 405 406 # pragma weak pth_mutex_init 407 # pragma weak pth_mutex_acquire 408 # pragma weak pth_mutex_release 409 # pragma weak pth_rwlock_init 410 # pragma weak pth_rwlock_acquire 411 # pragma weak pth_rwlock_release 412 # pragma weak pth_once 413 414 # pragma weak pth_cancel 415 # define pth_in_use() (pth_cancel != NULL) 416 417 # else 418 419 # define pth_in_use() 1 420 421 # endif 422 423 /* -------------------------- gl_lock_t datatype -------------------------- */ 424 425 typedef pth_mutex_t gl_lock_t; 426 # define gl_lock_define(STORAGECLASS, NAME) \ 427 STORAGECLASS pth_mutex_t NAME; 428 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 429 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer; 430 # define gl_lock_initializer \ 431 PTH_MUTEX_INIT 432 # define glthread_lock_init(LOCK) \ 433 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0) 434 # define glthread_lock_lock(LOCK) \ 435 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0) 436 # define glthread_lock_unlock(LOCK) \ 437 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0) 438 # define glthread_lock_destroy(LOCK) \ 439 ((void)(LOCK), 0) 440 441 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 442 443 /* Pth pth_rwlock_acquire always prefers readers. No autoconf test so far. */ 444 # if HAVE_PTH_RWLOCK_ACQUIRE_PREFER_WRITER 445 446 typedef pth_rwlock_t gl_rwlock_t; 447 # define gl_rwlock_define(STORAGECLASS, NAME) \ 448 STORAGECLASS pth_rwlock_t NAME; 449 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 450 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer; 451 # define gl_rwlock_initializer \ 452 PTH_RWLOCK_INIT 453 # define glthread_rwlock_init(LOCK) \ 454 (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0) 455 # define glthread_rwlock_rdlock(LOCK) \ 456 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0) 457 # define glthread_rwlock_wrlock(LOCK) \ 458 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0) 459 # define glthread_rwlock_unlock(LOCK) \ 460 (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0) 461 # define glthread_rwlock_destroy(LOCK) \ 462 ((void)(LOCK), 0) 463 464 # else 465 466 typedef struct 467 { 468 int initialized; 469 pth_mutex_t lock; /* protects the remaining fields */ 470 pth_cond_t waiting_readers; /* waiting readers */ 471 pth_cond_t waiting_writers; /* waiting writers */ 472 unsigned int waiting_writers_count; /* number of waiting writers */ 473 int runcount; /* number of readers running, or -1 when a writer runs */ 474 } 475 gl_rwlock_t; 476 # define gl_rwlock_define(STORAGECLASS, NAME) \ 477 STORAGECLASS gl_rwlock_t NAME; 478 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 479 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 480 # define gl_rwlock_initializer \ 481 { 0 } 482 # define glthread_rwlock_init(LOCK) \ 483 (pth_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0) 484 # define glthread_rwlock_rdlock(LOCK) \ 485 (pth_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0) 486 # define glthread_rwlock_wrlock(LOCK) \ 487 (pth_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0) 488 # define glthread_rwlock_unlock(LOCK) \ 489 (pth_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0) 490 # define glthread_rwlock_destroy(LOCK) \ 491 (pth_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0) 492 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock); 493 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock); 494 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock); 495 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock); 496 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock); 497 498 # endif 499 500 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 501 502 /* In Pth, mutexes are recursive by default. */ 503 typedef pth_mutex_t gl_recursive_lock_t; 504 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 505 STORAGECLASS pth_mutex_t NAME; 506 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 507 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer; 508 # define gl_recursive_lock_initializer \ 509 PTH_MUTEX_INIT 510 # define glthread_recursive_lock_init(LOCK) \ 511 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0) 512 # define glthread_recursive_lock_lock(LOCK) \ 513 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0) 514 # define glthread_recursive_lock_unlock(LOCK) \ 515 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0) 516 # define glthread_recursive_lock_destroy(LOCK) \ 517 ((void)(LOCK), 0) 518 519 /* -------------------------- gl_once_t datatype -------------------------- */ 520 521 typedef pth_once_t gl_once_t; 522 # define gl_once_define(STORAGECLASS, NAME) \ 523 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT; 524 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 525 (pth_in_use () \ 526 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \ 527 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) 528 extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void)); 529 extern int glthread_once_singlethreaded (pth_once_t *once_control); 530 531 # ifdef __cplusplus 532 } 533 # endif 534 535 #endif 536 537 /* ========================================================================= */ 538 539 #if USE_SOLARIS_THREADS 540 541 /* Use the old Solaris threads library. */ 542 543 # include <thread.h> 544 # include <synch.h> 545 546 # ifdef __cplusplus 547 extern "C" { 548 # endif 549 550 # if USE_SOLARIS_THREADS_WEAK 551 552 /* Use weak references to the old Solaris threads library. */ 553 554 # pragma weak mutex_init 555 # pragma weak mutex_lock 556 # pragma weak mutex_unlock 557 # pragma weak mutex_destroy 558 # pragma weak rwlock_init 559 # pragma weak rw_rdlock 560 # pragma weak rw_wrlock 561 # pragma weak rw_unlock 562 # pragma weak rwlock_destroy 563 # pragma weak thr_self 564 565 # pragma weak thr_suspend 566 # define thread_in_use() (thr_suspend != NULL) 567 568 # else 569 570 # define thread_in_use() 1 571 572 # endif 573 574 /* -------------------------- gl_lock_t datatype -------------------------- */ 575 576 typedef mutex_t gl_lock_t; 577 # define gl_lock_define(STORAGECLASS, NAME) \ 578 STORAGECLASS mutex_t NAME; 579 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 580 STORAGECLASS mutex_t NAME = gl_lock_initializer; 581 # define gl_lock_initializer \ 582 DEFAULTMUTEX 583 # define glthread_lock_init(LOCK) \ 584 (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0) 585 # define glthread_lock_lock(LOCK) \ 586 (thread_in_use () ? mutex_lock (LOCK) : 0) 587 # define glthread_lock_unlock(LOCK) \ 588 (thread_in_use () ? mutex_unlock (LOCK) : 0) 589 # define glthread_lock_destroy(LOCK) \ 590 (thread_in_use () ? mutex_destroy (LOCK) : 0) 591 592 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 593 594 typedef rwlock_t gl_rwlock_t; 595 # define gl_rwlock_define(STORAGECLASS, NAME) \ 596 STORAGECLASS rwlock_t NAME; 597 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 598 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer; 599 # define gl_rwlock_initializer \ 600 DEFAULTRWLOCK 601 # define glthread_rwlock_init(LOCK) \ 602 (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0) 603 # define glthread_rwlock_rdlock(LOCK) \ 604 (thread_in_use () ? rw_rdlock (LOCK) : 0) 605 # define glthread_rwlock_wrlock(LOCK) \ 606 (thread_in_use () ? rw_wrlock (LOCK) : 0) 607 # define glthread_rwlock_unlock(LOCK) \ 608 (thread_in_use () ? rw_unlock (LOCK) : 0) 609 # define glthread_rwlock_destroy(LOCK) \ 610 (thread_in_use () ? rwlock_destroy (LOCK) : 0) 611 612 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 613 614 /* Old Solaris threads did not have recursive locks. 615 We have to implement them ourselves. */ 616 617 typedef struct 618 { 619 mutex_t mutex; 620 thread_t owner; 621 unsigned long depth; 622 } 623 gl_recursive_lock_t; 624 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 625 STORAGECLASS gl_recursive_lock_t NAME; 626 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 627 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 628 # define gl_recursive_lock_initializer \ 629 { DEFAULTMUTEX, (thread_t) 0, 0 } 630 # define glthread_recursive_lock_init(LOCK) \ 631 (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 632 # define glthread_recursive_lock_lock(LOCK) \ 633 (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0) 634 # define glthread_recursive_lock_unlock(LOCK) \ 635 (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0) 636 # define glthread_recursive_lock_destroy(LOCK) \ 637 (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0) 638 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 639 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock); 640 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock); 641 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock); 642 643 /* -------------------------- gl_once_t datatype -------------------------- */ 644 645 typedef struct 646 { 647 volatile int inited; 648 mutex_t mutex; 649 } 650 gl_once_t; 651 # define gl_once_define(STORAGECLASS, NAME) \ 652 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX }; 653 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 654 (thread_in_use () \ 655 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \ 656 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) 657 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void)); 658 extern int glthread_once_singlethreaded (gl_once_t *once_control); 659 660 # ifdef __cplusplus 661 } 662 # endif 663 664 #endif 665 666 /* ========================================================================= */ 667 668 #if USE_WINDOWS_THREADS 669 670 # define WIN32_LEAN_AND_MEAN /* avoid including junk */ 671 # include <windows.h> 672 673 # ifdef __cplusplus 674 extern "C" { 675 # endif 676 677 /* We can use CRITICAL_SECTION directly, rather than the native Windows Event, 678 Mutex, Semaphore types, because 679 - we need only to synchronize inside a single process (address space), 680 not inter-process locking, 681 - we don't need to support trylock operations. (TryEnterCriticalSection 682 does not work on Windows 95/98/ME. Packages that need trylock usually 683 define their own mutex type.) */ 684 685 /* There is no way to statically initialize a CRITICAL_SECTION. It needs 686 to be done lazily, once only. For this we need spinlocks. */ 687 688 typedef struct { volatile int done; volatile long started; } gl_spinlock_t; 689 690 /* -------------------------- gl_lock_t datatype -------------------------- */ 691 692 typedef struct 693 { 694 gl_spinlock_t guard; /* protects the initialization */ 695 CRITICAL_SECTION lock; 696 } 697 gl_lock_t; 698 # define gl_lock_define(STORAGECLASS, NAME) \ 699 STORAGECLASS gl_lock_t NAME; 700 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 701 STORAGECLASS gl_lock_t NAME = gl_lock_initializer; 702 # define gl_lock_initializer \ 703 { { 0, -1 } } 704 # define glthread_lock_init(LOCK) \ 705 (glthread_lock_init_func (LOCK), 0) 706 # define glthread_lock_lock(LOCK) \ 707 glthread_lock_lock_func (LOCK) 708 # define glthread_lock_unlock(LOCK) \ 709 glthread_lock_unlock_func (LOCK) 710 # define glthread_lock_destroy(LOCK) \ 711 glthread_lock_destroy_func (LOCK) 712 extern void glthread_lock_init_func (gl_lock_t *lock); 713 extern int glthread_lock_lock_func (gl_lock_t *lock); 714 extern int glthread_lock_unlock_func (gl_lock_t *lock); 715 extern int glthread_lock_destroy_func (gl_lock_t *lock); 716 717 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 718 719 /* It is impossible to implement read-write locks using plain locks, without 720 introducing an extra thread dedicated to managing read-write locks. 721 Therefore here we need to use the low-level Event type. */ 722 723 typedef struct 724 { 725 HANDLE *array; /* array of waiting threads, each represented by an event */ 726 unsigned int count; /* number of waiting threads */ 727 unsigned int alloc; /* length of allocated array */ 728 unsigned int offset; /* index of first waiting thread in array */ 729 } 730 gl_carray_waitqueue_t; 731 typedef struct 732 { 733 gl_spinlock_t guard; /* protects the initialization */ 734 CRITICAL_SECTION lock; /* protects the remaining fields */ 735 gl_carray_waitqueue_t waiting_readers; /* waiting readers */ 736 gl_carray_waitqueue_t waiting_writers; /* waiting writers */ 737 int runcount; /* number of readers running, or -1 when a writer runs */ 738 } 739 gl_rwlock_t; 740 # define gl_rwlock_define(STORAGECLASS, NAME) \ 741 STORAGECLASS gl_rwlock_t NAME; 742 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 743 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 744 # define gl_rwlock_initializer \ 745 { { 0, -1 } } 746 # define glthread_rwlock_init(LOCK) \ 747 (glthread_rwlock_init_func (LOCK), 0) 748 # define glthread_rwlock_rdlock(LOCK) \ 749 glthread_rwlock_rdlock_func (LOCK) 750 # define glthread_rwlock_wrlock(LOCK) \ 751 glthread_rwlock_wrlock_func (LOCK) 752 # define glthread_rwlock_unlock(LOCK) \ 753 glthread_rwlock_unlock_func (LOCK) 754 # define glthread_rwlock_destroy(LOCK) \ 755 glthread_rwlock_destroy_func (LOCK) 756 extern void glthread_rwlock_init_func (gl_rwlock_t *lock); 757 extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock); 758 extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock); 759 extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock); 760 extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock); 761 762 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 763 764 /* The native Windows documentation says that CRITICAL_SECTION already 765 implements a recursive lock. But we need not rely on it: It's easy to 766 implement a recursive lock without this assumption. */ 767 768 typedef struct 769 { 770 gl_spinlock_t guard; /* protects the initialization */ 771 DWORD owner; 772 unsigned long depth; 773 CRITICAL_SECTION lock; 774 } 775 gl_recursive_lock_t; 776 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 777 STORAGECLASS gl_recursive_lock_t NAME; 778 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 779 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 780 # define gl_recursive_lock_initializer \ 781 { { 0, -1 }, 0, 0 } 782 # define glthread_recursive_lock_init(LOCK) \ 783 (glthread_recursive_lock_init_func (LOCK), 0) 784 # define glthread_recursive_lock_lock(LOCK) \ 785 glthread_recursive_lock_lock_func (LOCK) 786 # define glthread_recursive_lock_unlock(LOCK) \ 787 glthread_recursive_lock_unlock_func (LOCK) 788 # define glthread_recursive_lock_destroy(LOCK) \ 789 glthread_recursive_lock_destroy_func (LOCK) 790 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock); 791 extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock); 792 extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock); 793 extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock); 794 795 /* -------------------------- gl_once_t datatype -------------------------- */ 796 797 typedef struct 798 { 799 volatile int inited; 800 volatile long started; 801 CRITICAL_SECTION lock; 802 } 803 gl_once_t; 804 # define gl_once_define(STORAGECLASS, NAME) \ 805 STORAGECLASS gl_once_t NAME = { -1, -1 }; 806 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 807 (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0) 808 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void)); 809 810 # ifdef __cplusplus 811 } 812 # endif 813 814 #endif 815 816 /* ========================================================================= */ 817 818 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS) 819 820 /* Provide dummy implementation if threads are not supported. */ 821 822 /* -------------------------- gl_lock_t datatype -------------------------- */ 823 824 typedef int gl_lock_t; 825 # define gl_lock_define(STORAGECLASS, NAME) 826 # define gl_lock_define_initialized(STORAGECLASS, NAME) 827 # define glthread_lock_init(NAME) 0 828 # define glthread_lock_lock(NAME) 0 829 # define glthread_lock_unlock(NAME) 0 830 # define glthread_lock_destroy(NAME) 0 831 832 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 833 834 typedef int gl_rwlock_t; 835 # define gl_rwlock_define(STORAGECLASS, NAME) 836 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) 837 # define glthread_rwlock_init(NAME) 0 838 # define glthread_rwlock_rdlock(NAME) 0 839 # define glthread_rwlock_wrlock(NAME) 0 840 # define glthread_rwlock_unlock(NAME) 0 841 # define glthread_rwlock_destroy(NAME) 0 842 843 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 844 845 typedef int gl_recursive_lock_t; 846 # define gl_recursive_lock_define(STORAGECLASS, NAME) 847 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) 848 # define glthread_recursive_lock_init(NAME) 0 849 # define glthread_recursive_lock_lock(NAME) 0 850 # define glthread_recursive_lock_unlock(NAME) 0 851 # define glthread_recursive_lock_destroy(NAME) 0 852 853 /* -------------------------- gl_once_t datatype -------------------------- */ 854 855 typedef int gl_once_t; 856 # define gl_once_define(STORAGECLASS, NAME) \ 857 STORAGECLASS gl_once_t NAME = 0; 858 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 859 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0) 860 861 #endif 862 863 /* ========================================================================= */ 864 865 /* Macros with built-in error handling. */ 866 867 /* -------------------------- gl_lock_t datatype -------------------------- */ 868 869 #define gl_lock_init(NAME) \ 870 do \ 871 { \ 872 if (glthread_lock_init (&NAME)) \ 873 abort (); \ 874 } \ 875 while (0) 876 #define gl_lock_lock(NAME) \ 877 do \ 878 { \ 879 if (glthread_lock_lock (&NAME)) \ 880 abort (); \ 881 } \ 882 while (0) 883 #define gl_lock_unlock(NAME) \ 884 do \ 885 { \ 886 if (glthread_lock_unlock (&NAME)) \ 887 abort (); \ 888 } \ 889 while (0) 890 #define gl_lock_destroy(NAME) \ 891 do \ 892 { \ 893 if (glthread_lock_destroy (&NAME)) \ 894 abort (); \ 895 } \ 896 while (0) 897 898 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 899 900 #define gl_rwlock_init(NAME) \ 901 do \ 902 { \ 903 if (glthread_rwlock_init (&NAME)) \ 904 abort (); \ 905 } \ 906 while (0) 907 #define gl_rwlock_rdlock(NAME) \ 908 do \ 909 { \ 910 if (glthread_rwlock_rdlock (&NAME)) \ 911 abort (); \ 912 } \ 913 while (0) 914 #define gl_rwlock_wrlock(NAME) \ 915 do \ 916 { \ 917 if (glthread_rwlock_wrlock (&NAME)) \ 918 abort (); \ 919 } \ 920 while (0) 921 #define gl_rwlock_unlock(NAME) \ 922 do \ 923 { \ 924 if (glthread_rwlock_unlock (&NAME)) \ 925 abort (); \ 926 } \ 927 while (0) 928 #define gl_rwlock_destroy(NAME) \ 929 do \ 930 { \ 931 if (glthread_rwlock_destroy (&NAME)) \ 932 abort (); \ 933 } \ 934 while (0) 935 936 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 937 938 #define gl_recursive_lock_init(NAME) \ 939 do \ 940 { \ 941 if (glthread_recursive_lock_init (&NAME)) \ 942 abort (); \ 943 } \ 944 while (0) 945 #define gl_recursive_lock_lock(NAME) \ 946 do \ 947 { \ 948 if (glthread_recursive_lock_lock (&NAME)) \ 949 abort (); \ 950 } \ 951 while (0) 952 #define gl_recursive_lock_unlock(NAME) \ 953 do \ 954 { \ 955 if (glthread_recursive_lock_unlock (&NAME)) \ 956 abort (); \ 957 } \ 958 while (0) 959 #define gl_recursive_lock_destroy(NAME) \ 960 do \ 961 { \ 962 if (glthread_recursive_lock_destroy (&NAME)) \ 963 abort (); \ 964 } \ 965 while (0) 966 967 /* -------------------------- gl_once_t datatype -------------------------- */ 968 969 #define gl_once(NAME, INITFUNCTION) \ 970 do \ 971 { \ 972 if (glthread_once (&NAME, INITFUNCTION)) \ 973 abort (); \ 974 } \ 975 while (0) 976 977 /* ========================================================================= */ 978 979 #endif /* _LOCK_H */ 980