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