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