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