1 /* Locking in multithreaded situations. 2 Copyright (C) 2005-2012 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 <http://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 # ifndef pthread_self 143 # pragma weak pthread_self 144 # endif 145 146 # if !PTHREAD_IN_USE_DETECTION_HARD 147 # pragma weak pthread_cancel 148 # define pthread_in_use() (pthread_cancel != NULL) 149 # endif 150 151 # else 152 153 # if !PTHREAD_IN_USE_DETECTION_HARD 154 # define pthread_in_use() 1 155 # endif 156 157 # endif 158 159 /* -------------------------- gl_lock_t datatype -------------------------- */ 160 161 typedef pthread_mutex_t gl_lock_t; 162 # define gl_lock_define(STORAGECLASS, NAME) \ 163 STORAGECLASS pthread_mutex_t NAME; 164 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 165 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer; 166 # define gl_lock_initializer \ 167 PTHREAD_MUTEX_INITIALIZER 168 # define glthread_lock_init(LOCK) \ 169 (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0) 170 # define glthread_lock_lock(LOCK) \ 171 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0) 172 # define glthread_lock_unlock(LOCK) \ 173 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0) 174 # define glthread_lock_destroy(LOCK) \ 175 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0) 176 177 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 178 179 # if HAVE_PTHREAD_RWLOCK 180 181 # ifdef PTHREAD_RWLOCK_INITIALIZER 182 183 typedef pthread_rwlock_t gl_rwlock_t; 184 # define gl_rwlock_define(STORAGECLASS, NAME) \ 185 STORAGECLASS pthread_rwlock_t NAME; 186 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 187 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer; 188 # define gl_rwlock_initializer \ 189 PTHREAD_RWLOCK_INITIALIZER 190 # define glthread_rwlock_init(LOCK) \ 191 (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0) 192 # define glthread_rwlock_rdlock(LOCK) \ 193 (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0) 194 # define glthread_rwlock_wrlock(LOCK) \ 195 (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0) 196 # define glthread_rwlock_unlock(LOCK) \ 197 (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0) 198 # define glthread_rwlock_destroy(LOCK) \ 199 (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0) 200 201 # else 202 203 typedef struct 204 { 205 int initialized; 206 pthread_mutex_t guard; /* protects the initialization */ 207 pthread_rwlock_t rwlock; /* read-write lock */ 208 } 209 gl_rwlock_t; 210 # define gl_rwlock_define(STORAGECLASS, NAME) \ 211 STORAGECLASS gl_rwlock_t NAME; 212 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 213 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 214 # define gl_rwlock_initializer \ 215 { 0, PTHREAD_MUTEX_INITIALIZER } 216 # define glthread_rwlock_init(LOCK) \ 217 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0) 218 # define glthread_rwlock_rdlock(LOCK) \ 219 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0) 220 # define glthread_rwlock_wrlock(LOCK) \ 221 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0) 222 # define glthread_rwlock_unlock(LOCK) \ 223 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0) 224 # define glthread_rwlock_destroy(LOCK) \ 225 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0) 226 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock); 227 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock); 228 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock); 229 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock); 230 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock); 231 232 # endif 233 234 # else 235 236 typedef struct 237 { 238 pthread_mutex_t lock; /* protects the remaining fields */ 239 pthread_cond_t waiting_readers; /* waiting readers */ 240 pthread_cond_t waiting_writers; /* waiting writers */ 241 unsigned int waiting_writers_count; /* number of waiting writers */ 242 int runcount; /* number of readers running, or -1 when a writer runs */ 243 } 244 gl_rwlock_t; 245 # define gl_rwlock_define(STORAGECLASS, NAME) \ 246 STORAGECLASS gl_rwlock_t NAME; 247 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 248 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 249 # define gl_rwlock_initializer \ 250 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 } 251 # define glthread_rwlock_init(LOCK) \ 252 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0) 253 # define glthread_rwlock_rdlock(LOCK) \ 254 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0) 255 # define glthread_rwlock_wrlock(LOCK) \ 256 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0) 257 # define glthread_rwlock_unlock(LOCK) \ 258 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0) 259 # define glthread_rwlock_destroy(LOCK) \ 260 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0) 261 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock); 262 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock); 263 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock); 264 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock); 265 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock); 266 267 # endif 268 269 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 270 271 # if HAVE_PTHREAD_MUTEX_RECURSIVE 272 273 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 274 275 typedef pthread_mutex_t gl_recursive_lock_t; 276 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 277 STORAGECLASS pthread_mutex_t NAME; 278 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 279 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer; 280 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER 281 # define gl_recursive_lock_initializer \ 282 PTHREAD_RECURSIVE_MUTEX_INITIALIZER 283 # else 284 # define gl_recursive_lock_initializer \ 285 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 286 # endif 287 # define glthread_recursive_lock_init(LOCK) \ 288 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 289 # define glthread_recursive_lock_lock(LOCK) \ 290 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0) 291 # define glthread_recursive_lock_unlock(LOCK) \ 292 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0) 293 # define glthread_recursive_lock_destroy(LOCK) \ 294 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0) 295 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 296 297 # else 298 299 typedef struct 300 { 301 pthread_mutex_t recmutex; /* recursive mutex */ 302 pthread_mutex_t guard; /* protects the initialization */ 303 int initialized; 304 } 305 gl_recursive_lock_t; 306 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 307 STORAGECLASS gl_recursive_lock_t NAME; 308 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 309 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 310 # define gl_recursive_lock_initializer \ 311 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 } 312 # define glthread_recursive_lock_init(LOCK) \ 313 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 314 # define glthread_recursive_lock_lock(LOCK) \ 315 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0) 316 # define glthread_recursive_lock_unlock(LOCK) \ 317 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0) 318 # define glthread_recursive_lock_destroy(LOCK) \ 319 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0) 320 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 321 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock); 322 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock); 323 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock); 324 325 # endif 326 327 # else 328 329 /* Old versions of POSIX threads on Solaris did not have recursive locks. 330 We have to implement them ourselves. */ 331 332 typedef struct 333 { 334 pthread_mutex_t mutex; 335 pthread_t owner; 336 unsigned long depth; 337 } 338 gl_recursive_lock_t; 339 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 340 STORAGECLASS gl_recursive_lock_t NAME; 341 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 342 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 343 # define gl_recursive_lock_initializer \ 344 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 } 345 # define glthread_recursive_lock_init(LOCK) \ 346 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 347 # define glthread_recursive_lock_lock(LOCK) \ 348 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0) 349 # define glthread_recursive_lock_unlock(LOCK) \ 350 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0) 351 # define glthread_recursive_lock_destroy(LOCK) \ 352 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0) 353 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 354 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock); 355 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock); 356 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock); 357 358 # endif 359 360 /* -------------------------- gl_once_t datatype -------------------------- */ 361 362 typedef pthread_once_t gl_once_t; 363 # define gl_once_define(STORAGECLASS, NAME) \ 364 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT; 365 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 366 (pthread_in_use () \ 367 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \ 368 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) 369 extern int glthread_once_singlethreaded (pthread_once_t *once_control); 370 371 # ifdef __cplusplus 372 } 373 # endif 374 375 #endif 376 377 /* ========================================================================= */ 378 379 #if USE_PTH_THREADS 380 381 /* Use the GNU Pth threads library. */ 382 383 # include <pth.h> 384 385 # ifdef __cplusplus 386 extern "C" { 387 # endif 388 389 # if USE_PTH_THREADS_WEAK 390 391 /* Use weak references to the GNU Pth threads library. */ 392 393 # pragma weak pth_mutex_init 394 # pragma weak pth_mutex_acquire 395 # pragma weak pth_mutex_release 396 # pragma weak pth_rwlock_init 397 # pragma weak pth_rwlock_acquire 398 # pragma weak pth_rwlock_release 399 # pragma weak pth_once 400 401 # pragma weak pth_cancel 402 # define pth_in_use() (pth_cancel != NULL) 403 404 # else 405 406 # define pth_in_use() 1 407 408 # endif 409 410 /* -------------------------- gl_lock_t datatype -------------------------- */ 411 412 typedef pth_mutex_t gl_lock_t; 413 # define gl_lock_define(STORAGECLASS, NAME) \ 414 STORAGECLASS pth_mutex_t NAME; 415 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 416 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer; 417 # define gl_lock_initializer \ 418 PTH_MUTEX_INIT 419 # define glthread_lock_init(LOCK) \ 420 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0) 421 # define glthread_lock_lock(LOCK) \ 422 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0) 423 # define glthread_lock_unlock(LOCK) \ 424 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0) 425 # define glthread_lock_destroy(LOCK) \ 426 ((void)(LOCK), 0) 427 428 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 429 430 typedef pth_rwlock_t gl_rwlock_t; 431 # define gl_rwlock_define(STORAGECLASS, NAME) \ 432 STORAGECLASS pth_rwlock_t NAME; 433 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 434 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer; 435 # define gl_rwlock_initializer \ 436 PTH_RWLOCK_INIT 437 # define glthread_rwlock_init(LOCK) \ 438 (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0) 439 # define glthread_rwlock_rdlock(LOCK) \ 440 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0) 441 # define glthread_rwlock_wrlock(LOCK) \ 442 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0) 443 # define glthread_rwlock_unlock(LOCK) \ 444 (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0) 445 # define glthread_rwlock_destroy(LOCK) \ 446 ((void)(LOCK), 0) 447 448 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 449 450 /* In Pth, mutexes are recursive by default. */ 451 typedef pth_mutex_t gl_recursive_lock_t; 452 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 453 STORAGECLASS pth_mutex_t NAME; 454 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 455 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer; 456 # define gl_recursive_lock_initializer \ 457 PTH_MUTEX_INIT 458 # define glthread_recursive_lock_init(LOCK) \ 459 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0) 460 # define glthread_recursive_lock_lock(LOCK) \ 461 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0) 462 # define glthread_recursive_lock_unlock(LOCK) \ 463 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0) 464 # define glthread_recursive_lock_destroy(LOCK) \ 465 ((void)(LOCK), 0) 466 467 /* -------------------------- gl_once_t datatype -------------------------- */ 468 469 typedef pth_once_t gl_once_t; 470 # define gl_once_define(STORAGECLASS, NAME) \ 471 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT; 472 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 473 (pth_in_use () \ 474 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \ 475 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) 476 extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void)); 477 extern int glthread_once_singlethreaded (pth_once_t *once_control); 478 479 # ifdef __cplusplus 480 } 481 # endif 482 483 #endif 484 485 /* ========================================================================= */ 486 487 #if USE_SOLARIS_THREADS 488 489 /* Use the old Solaris threads library. */ 490 491 # include <thread.h> 492 # include <synch.h> 493 494 # ifdef __cplusplus 495 extern "C" { 496 # endif 497 498 # if USE_SOLARIS_THREADS_WEAK 499 500 /* Use weak references to the old Solaris threads library. */ 501 502 # pragma weak mutex_init 503 # pragma weak mutex_lock 504 # pragma weak mutex_unlock 505 # pragma weak mutex_destroy 506 # pragma weak rwlock_init 507 # pragma weak rw_rdlock 508 # pragma weak rw_wrlock 509 # pragma weak rw_unlock 510 # pragma weak rwlock_destroy 511 # pragma weak thr_self 512 513 # pragma weak thr_suspend 514 # define thread_in_use() (thr_suspend != NULL) 515 516 # else 517 518 # define thread_in_use() 1 519 520 # endif 521 522 /* -------------------------- gl_lock_t datatype -------------------------- */ 523 524 typedef mutex_t gl_lock_t; 525 # define gl_lock_define(STORAGECLASS, NAME) \ 526 STORAGECLASS mutex_t NAME; 527 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 528 STORAGECLASS mutex_t NAME = gl_lock_initializer; 529 # define gl_lock_initializer \ 530 DEFAULTMUTEX 531 # define glthread_lock_init(LOCK) \ 532 (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0) 533 # define glthread_lock_lock(LOCK) \ 534 (thread_in_use () ? mutex_lock (LOCK) : 0) 535 # define glthread_lock_unlock(LOCK) \ 536 (thread_in_use () ? mutex_unlock (LOCK) : 0) 537 # define glthread_lock_destroy(LOCK) \ 538 (thread_in_use () ? mutex_destroy (LOCK) : 0) 539 540 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 541 542 typedef rwlock_t gl_rwlock_t; 543 # define gl_rwlock_define(STORAGECLASS, NAME) \ 544 STORAGECLASS rwlock_t NAME; 545 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 546 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer; 547 # define gl_rwlock_initializer \ 548 DEFAULTRWLOCK 549 # define glthread_rwlock_init(LOCK) \ 550 (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0) 551 # define glthread_rwlock_rdlock(LOCK) \ 552 (thread_in_use () ? rw_rdlock (LOCK) : 0) 553 # define glthread_rwlock_wrlock(LOCK) \ 554 (thread_in_use () ? rw_wrlock (LOCK) : 0) 555 # define glthread_rwlock_unlock(LOCK) \ 556 (thread_in_use () ? rw_unlock (LOCK) : 0) 557 # define glthread_rwlock_destroy(LOCK) \ 558 (thread_in_use () ? rwlock_destroy (LOCK) : 0) 559 560 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 561 562 /* Old Solaris threads did not have recursive locks. 563 We have to implement them ourselves. */ 564 565 typedef struct 566 { 567 mutex_t mutex; 568 thread_t owner; 569 unsigned long depth; 570 } 571 gl_recursive_lock_t; 572 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 573 STORAGECLASS gl_recursive_lock_t NAME; 574 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 575 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 576 # define gl_recursive_lock_initializer \ 577 { DEFAULTMUTEX, (thread_t) 0, 0 } 578 # define glthread_recursive_lock_init(LOCK) \ 579 (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0) 580 # define glthread_recursive_lock_lock(LOCK) \ 581 (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0) 582 # define glthread_recursive_lock_unlock(LOCK) \ 583 (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0) 584 # define glthread_recursive_lock_destroy(LOCK) \ 585 (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0) 586 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock); 587 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock); 588 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock); 589 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock); 590 591 /* -------------------------- gl_once_t datatype -------------------------- */ 592 593 typedef struct 594 { 595 volatile int inited; 596 mutex_t mutex; 597 } 598 gl_once_t; 599 # define gl_once_define(STORAGECLASS, NAME) \ 600 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX }; 601 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 602 (thread_in_use () \ 603 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \ 604 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0)) 605 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void)); 606 extern int glthread_once_singlethreaded (gl_once_t *once_control); 607 608 # ifdef __cplusplus 609 } 610 # endif 611 612 #endif 613 614 /* ========================================================================= */ 615 616 #if USE_WINDOWS_THREADS 617 618 # define WIN32_LEAN_AND_MEAN /* avoid including junk */ 619 # include <windows.h> 620 621 # ifdef __cplusplus 622 extern "C" { 623 # endif 624 625 /* We can use CRITICAL_SECTION directly, rather than the native Windows Event, 626 Mutex, Semaphore types, because 627 - we need only to synchronize inside a single process (address space), 628 not inter-process locking, 629 - we don't need to support trylock operations. (TryEnterCriticalSection 630 does not work on Windows 95/98/ME. Packages that need trylock usually 631 define their own mutex type.) */ 632 633 /* There is no way to statically initialize a CRITICAL_SECTION. It needs 634 to be done lazily, once only. For this we need spinlocks. */ 635 636 typedef struct { volatile int done; volatile long started; } gl_spinlock_t; 637 638 /* -------------------------- gl_lock_t datatype -------------------------- */ 639 640 typedef struct 641 { 642 gl_spinlock_t guard; /* protects the initialization */ 643 CRITICAL_SECTION lock; 644 } 645 gl_lock_t; 646 # define gl_lock_define(STORAGECLASS, NAME) \ 647 STORAGECLASS gl_lock_t NAME; 648 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 649 STORAGECLASS gl_lock_t NAME = gl_lock_initializer; 650 # define gl_lock_initializer \ 651 { { 0, -1 } } 652 # define glthread_lock_init(LOCK) \ 653 (glthread_lock_init_func (LOCK), 0) 654 # define glthread_lock_lock(LOCK) \ 655 glthread_lock_lock_func (LOCK) 656 # define glthread_lock_unlock(LOCK) \ 657 glthread_lock_unlock_func (LOCK) 658 # define glthread_lock_destroy(LOCK) \ 659 glthread_lock_destroy_func (LOCK) 660 extern void glthread_lock_init_func (gl_lock_t *lock); 661 extern int glthread_lock_lock_func (gl_lock_t *lock); 662 extern int glthread_lock_unlock_func (gl_lock_t *lock); 663 extern int glthread_lock_destroy_func (gl_lock_t *lock); 664 665 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 666 667 /* It is impossible to implement read-write locks using plain locks, without 668 introducing an extra thread dedicated to managing read-write locks. 669 Therefore here we need to use the low-level Event type. */ 670 671 typedef struct 672 { 673 HANDLE *array; /* array of waiting threads, each represented by an event */ 674 unsigned int count; /* number of waiting threads */ 675 unsigned int alloc; /* length of allocated array */ 676 unsigned int offset; /* index of first waiting thread in array */ 677 } 678 gl_carray_waitqueue_t; 679 typedef struct 680 { 681 gl_spinlock_t guard; /* protects the initialization */ 682 CRITICAL_SECTION lock; /* protects the remaining fields */ 683 gl_carray_waitqueue_t waiting_readers; /* waiting readers */ 684 gl_carray_waitqueue_t waiting_writers; /* waiting writers */ 685 int runcount; /* number of readers running, or -1 when a writer runs */ 686 } 687 gl_rwlock_t; 688 # define gl_rwlock_define(STORAGECLASS, NAME) \ 689 STORAGECLASS gl_rwlock_t NAME; 690 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 691 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 692 # define gl_rwlock_initializer \ 693 { { 0, -1 } } 694 # define glthread_rwlock_init(LOCK) \ 695 (glthread_rwlock_init_func (LOCK), 0) 696 # define glthread_rwlock_rdlock(LOCK) \ 697 glthread_rwlock_rdlock_func (LOCK) 698 # define glthread_rwlock_wrlock(LOCK) \ 699 glthread_rwlock_wrlock_func (LOCK) 700 # define glthread_rwlock_unlock(LOCK) \ 701 glthread_rwlock_unlock_func (LOCK) 702 # define glthread_rwlock_destroy(LOCK) \ 703 glthread_rwlock_destroy_func (LOCK) 704 extern void glthread_rwlock_init_func (gl_rwlock_t *lock); 705 extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock); 706 extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock); 707 extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock); 708 extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock); 709 710 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 711 712 /* The native Windows documentation says that CRITICAL_SECTION already 713 implements a recursive lock. But we need not rely on it: It's easy to 714 implement a recursive lock without this assumption. */ 715 716 typedef struct 717 { 718 gl_spinlock_t guard; /* protects the initialization */ 719 DWORD owner; 720 unsigned long depth; 721 CRITICAL_SECTION lock; 722 } 723 gl_recursive_lock_t; 724 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 725 STORAGECLASS gl_recursive_lock_t NAME; 726 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 727 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 728 # define gl_recursive_lock_initializer \ 729 { { 0, -1 }, 0, 0 } 730 # define glthread_recursive_lock_init(LOCK) \ 731 (glthread_recursive_lock_init_func (LOCK), 0) 732 # define glthread_recursive_lock_lock(LOCK) \ 733 glthread_recursive_lock_lock_func (LOCK) 734 # define glthread_recursive_lock_unlock(LOCK) \ 735 glthread_recursive_lock_unlock_func (LOCK) 736 # define glthread_recursive_lock_destroy(LOCK) \ 737 glthread_recursive_lock_destroy_func (LOCK) 738 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock); 739 extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock); 740 extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock); 741 extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock); 742 743 /* -------------------------- gl_once_t datatype -------------------------- */ 744 745 typedef struct 746 { 747 volatile int inited; 748 volatile long started; 749 CRITICAL_SECTION lock; 750 } 751 gl_once_t; 752 # define gl_once_define(STORAGECLASS, NAME) \ 753 STORAGECLASS gl_once_t NAME = { -1, -1 }; 754 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 755 (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0) 756 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void)); 757 758 # ifdef __cplusplus 759 } 760 # endif 761 762 #endif 763 764 /* ========================================================================= */ 765 766 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS) 767 768 /* Provide dummy implementation if threads are not supported. */ 769 770 /* -------------------------- gl_lock_t datatype -------------------------- */ 771 772 typedef int gl_lock_t; 773 # define gl_lock_define(STORAGECLASS, NAME) 774 # define gl_lock_define_initialized(STORAGECLASS, NAME) 775 # define glthread_lock_init(NAME) 0 776 # define glthread_lock_lock(NAME) 0 777 # define glthread_lock_unlock(NAME) 0 778 # define glthread_lock_destroy(NAME) 0 779 780 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 781 782 typedef int gl_rwlock_t; 783 # define gl_rwlock_define(STORAGECLASS, NAME) 784 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) 785 # define glthread_rwlock_init(NAME) 0 786 # define glthread_rwlock_rdlock(NAME) 0 787 # define glthread_rwlock_wrlock(NAME) 0 788 # define glthread_rwlock_unlock(NAME) 0 789 # define glthread_rwlock_destroy(NAME) 0 790 791 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 792 793 typedef int gl_recursive_lock_t; 794 # define gl_recursive_lock_define(STORAGECLASS, NAME) 795 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) 796 # define glthread_recursive_lock_init(NAME) 0 797 # define glthread_recursive_lock_lock(NAME) 0 798 # define glthread_recursive_lock_unlock(NAME) 0 799 # define glthread_recursive_lock_destroy(NAME) 0 800 801 /* -------------------------- gl_once_t datatype -------------------------- */ 802 803 typedef int gl_once_t; 804 # define gl_once_define(STORAGECLASS, NAME) \ 805 STORAGECLASS gl_once_t NAME = 0; 806 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 807 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0) 808 809 #endif 810 811 /* ========================================================================= */ 812 813 /* Macros with built-in error handling. */ 814 815 /* -------------------------- gl_lock_t datatype -------------------------- */ 816 817 #define gl_lock_init(NAME) \ 818 do \ 819 { \ 820 if (glthread_lock_init (&NAME)) \ 821 abort (); \ 822 } \ 823 while (0) 824 #define gl_lock_lock(NAME) \ 825 do \ 826 { \ 827 if (glthread_lock_lock (&NAME)) \ 828 abort (); \ 829 } \ 830 while (0) 831 #define gl_lock_unlock(NAME) \ 832 do \ 833 { \ 834 if (glthread_lock_unlock (&NAME)) \ 835 abort (); \ 836 } \ 837 while (0) 838 #define gl_lock_destroy(NAME) \ 839 do \ 840 { \ 841 if (glthread_lock_destroy (&NAME)) \ 842 abort (); \ 843 } \ 844 while (0) 845 846 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 847 848 #define gl_rwlock_init(NAME) \ 849 do \ 850 { \ 851 if (glthread_rwlock_init (&NAME)) \ 852 abort (); \ 853 } \ 854 while (0) 855 #define gl_rwlock_rdlock(NAME) \ 856 do \ 857 { \ 858 if (glthread_rwlock_rdlock (&NAME)) \ 859 abort (); \ 860 } \ 861 while (0) 862 #define gl_rwlock_wrlock(NAME) \ 863 do \ 864 { \ 865 if (glthread_rwlock_wrlock (&NAME)) \ 866 abort (); \ 867 } \ 868 while (0) 869 #define gl_rwlock_unlock(NAME) \ 870 do \ 871 { \ 872 if (glthread_rwlock_unlock (&NAME)) \ 873 abort (); \ 874 } \ 875 while (0) 876 #define gl_rwlock_destroy(NAME) \ 877 do \ 878 { \ 879 if (glthread_rwlock_destroy (&NAME)) \ 880 abort (); \ 881 } \ 882 while (0) 883 884 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 885 886 #define gl_recursive_lock_init(NAME) \ 887 do \ 888 { \ 889 if (glthread_recursive_lock_init (&NAME)) \ 890 abort (); \ 891 } \ 892 while (0) 893 #define gl_recursive_lock_lock(NAME) \ 894 do \ 895 { \ 896 if (glthread_recursive_lock_lock (&NAME)) \ 897 abort (); \ 898 } \ 899 while (0) 900 #define gl_recursive_lock_unlock(NAME) \ 901 do \ 902 { \ 903 if (glthread_recursive_lock_unlock (&NAME)) \ 904 abort (); \ 905 } \ 906 while (0) 907 #define gl_recursive_lock_destroy(NAME) \ 908 do \ 909 { \ 910 if (glthread_recursive_lock_destroy (&NAME)) \ 911 abort (); \ 912 } \ 913 while (0) 914 915 /* -------------------------- gl_once_t datatype -------------------------- */ 916 917 #define gl_once(NAME, INITFUNCTION) \ 918 do \ 919 { \ 920 if (glthread_once (&NAME, INITFUNCTION)) \ 921 abort (); \ 922 } \ 923 while (0) 924 925 /* ========================================================================= */ 926 927 #endif /* _LOCK_H */ 928