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