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