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