1 /* Locking in multithreaded situations. 2 Copyright (C) 2005-2009 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 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 84 /* ========================================================================= */ 85 86 #if USE_POSIX_THREADS 87 88 /* Use the POSIX threads library. */ 89 90 # include <pthread.h> 91 # include <stdlib.h> 92 93 # ifdef __cplusplus 94 extern "C" { 95 # endif 96 97 /* -------------------------- gl_lock_t datatype -------------------------- */ 98 99 typedef pthread_mutex_t gl_lock_t; 100 # define gl_lock_define(STORAGECLASS, NAME) \ 101 STORAGECLASS pthread_mutex_t NAME; 102 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 103 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer; 104 # define gl_lock_initializer \ 105 PTHREAD_MUTEX_INITIALIZER 106 # define glthread_lock_init(LOCK) \ 107 (pthread_mutex_init (LOCK, NULL)) 108 # define glthread_lock_lock(LOCK) \ 109 (pthread_mutex_lock (LOCK)) 110 # define glthread_lock_unlock(LOCK) \ 111 (pthread_mutex_unlock (LOCK)) 112 # define glthread_lock_destroy(LOCK) \ 113 (pthread_mutex_destroy (LOCK)) 114 115 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 116 117 # if HAVE_PTHREAD_RWLOCK 118 119 # ifdef PTHREAD_RWLOCK_INITIALIZER 120 121 typedef pthread_rwlock_t gl_rwlock_t; 122 # define gl_rwlock_define(STORAGECLASS, NAME) \ 123 STORAGECLASS pthread_rwlock_t NAME; 124 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 125 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer; 126 # define gl_rwlock_initializer \ 127 PTHREAD_RWLOCK_INITIALIZER 128 # define glthread_rwlock_init(LOCK) \ 129 (pthread_rwlock_init (LOCK, NULL)) 130 # define glthread_rwlock_rdlock(LOCK) \ 131 (pthread_rwlock_rdlock (LOCK)) 132 # define glthread_rwlock_wrlock(LOCK) \ 133 (pthread_rwlock_wrlock (LOCK)) 134 # define glthread_rwlock_unlock(LOCK) \ 135 (pthread_rwlock_unlock (LOCK)) 136 # define glthread_rwlock_destroy(LOCK) \ 137 (pthread_rwlock_destroy (LOCK)) 138 139 # else 140 141 typedef struct 142 { 143 int initialized; 144 pthread_mutex_t guard; /* protects the initialization */ 145 pthread_rwlock_t rwlock; /* read-write lock */ 146 } 147 gl_rwlock_t; 148 # define gl_rwlock_define(STORAGECLASS, NAME) \ 149 STORAGECLASS gl_rwlock_t NAME; 150 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 151 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 152 # define gl_rwlock_initializer \ 153 { 0, PTHREAD_MUTEX_INITIALIZER } 154 extern int glthread_rwlock_init (gl_rwlock_t *lock); 155 extern int glthread_rwlock_rdlock (gl_rwlock_t *lock); 156 extern int glthread_rwlock_wrlock (gl_rwlock_t *lock); 157 extern int glthread_rwlock_unlock (gl_rwlock_t *lock); 158 extern int glthread_rwlock_destroy (gl_rwlock_t *lock); 159 160 # endif 161 162 # else 163 164 typedef struct 165 { 166 pthread_mutex_t lock; /* protects the remaining fields */ 167 pthread_cond_t waiting_readers; /* waiting readers */ 168 pthread_cond_t waiting_writers; /* waiting writers */ 169 unsigned int waiting_writers_count; /* number of waiting writers */ 170 int runcount; /* number of readers running, or -1 when a writer runs */ 171 } 172 gl_rwlock_t; 173 # define gl_rwlock_define(STORAGECLASS, NAME) \ 174 STORAGECLASS gl_rwlock_t NAME; 175 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 176 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 177 # define gl_rwlock_initializer \ 178 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 } 179 extern int glthread_rwlock_init (gl_rwlock_t *lock); 180 extern int glthread_rwlock_rdlock (gl_rwlock_t *lock); 181 extern int glthread_rwlock_wrlock (gl_rwlock_t *lock); 182 extern int glthread_rwlock_unlock (gl_rwlock_t *lock); 183 extern int glthread_rwlock_destroy (gl_rwlock_t *lock); 184 185 # endif 186 187 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 188 189 # if HAVE_PTHREAD_MUTEX_RECURSIVE 190 191 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 192 193 typedef pthread_mutex_t gl_recursive_lock_t; 194 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 195 STORAGECLASS pthread_mutex_t NAME; 196 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 197 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer; 198 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER 199 # define gl_recursive_lock_initializer \ 200 PTHREAD_RECURSIVE_MUTEX_INITIALIZER 201 # else 202 # define gl_recursive_lock_initializer \ 203 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 204 # endif 205 # define glthread_recursive_lock_lock(LOCK) \ 206 (pthread_mutex_lock (LOCK)) 207 # define glthread_recursive_lock_unlock(LOCK) \ 208 (pthread_mutex_unlock (LOCK)) 209 # define glthread_recursive_lock_destroy(LOCK) \ 210 (pthread_mutex_destroy (LOCK)) 211 extern int glthread_recursive_lock_init (gl_recursive_lock_t *lock); 212 213 # else 214 215 typedef struct 216 { 217 pthread_mutex_t recmutex; /* recursive mutex */ 218 pthread_mutex_t guard; /* protects the initialization */ 219 int initialized; 220 } 221 gl_recursive_lock_t; 222 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 223 STORAGECLASS gl_recursive_lock_t NAME; 224 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 225 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 226 # define gl_recursive_lock_initializer \ 227 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 } 228 extern int glthread_recursive_lock_init (gl_recursive_lock_t *lock); 229 extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock); 230 extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock); 231 extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); 232 233 # endif 234 235 # else 236 237 /* Old versions of POSIX threads on Solaris did not have recursive locks. 238 We have to implement them ourselves. */ 239 240 typedef struct 241 { 242 pthread_mutex_t mutex; 243 pthread_t owner; 244 unsigned long depth; 245 } 246 gl_recursive_lock_t; 247 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 248 STORAGECLASS gl_recursive_lock_t NAME; 249 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 250 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 251 # define gl_recursive_lock_initializer \ 252 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 } 253 extern int glthread_recursive_lock_init (gl_recursive_lock_t *lock); 254 extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock); 255 extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock); 256 extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); 257 258 # endif 259 260 /* -------------------------- gl_once_t datatype -------------------------- */ 261 262 typedef pthread_once_t gl_once_t; 263 # define gl_once_define(STORAGECLASS, NAME) \ 264 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT; 265 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 266 (pthread_once (ONCE_CONTROL, INITFUNCTION)) 267 268 # ifdef __cplusplus 269 } 270 # endif 271 272 #endif 273 274 /* ========================================================================= */ 275 276 #if USE_WIN32_THREADS 277 278 # include <windows.h> 279 280 # ifdef __cplusplus 281 extern "C" { 282 # endif 283 284 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex, 285 Semaphore types, because 286 - we need only to synchronize inside a single process (address space), 287 not inter-process locking, 288 - we don't need to support trylock operations. (TryEnterCriticalSection 289 does not work on Windows 95/98/ME. Packages that need trylock usually 290 define their own mutex type.) */ 291 292 /* There is no way to statically initialize a CRITICAL_SECTION. It needs 293 to be done lazily, once only. For this we need spinlocks. */ 294 295 typedef struct { volatile int done; volatile long started; } gl_spinlock_t; 296 297 /* -------------------------- gl_lock_t datatype -------------------------- */ 298 299 typedef struct 300 { 301 gl_spinlock_t guard; /* protects the initialization */ 302 CRITICAL_SECTION lock; 303 } 304 gl_lock_t; 305 # define gl_lock_define(STORAGECLASS, NAME) \ 306 STORAGECLASS gl_lock_t NAME; 307 # define gl_lock_define_initialized(STORAGECLASS, NAME) \ 308 STORAGECLASS gl_lock_t NAME = gl_lock_initializer; 309 # define gl_lock_initializer \ 310 { { 0, -1 } } 311 # define glthread_lock_init(LOCK) \ 312 (glthread_lock_init_func (LOCK), 0) 313 extern void glthread_lock_init_func (gl_lock_t *lock); 314 extern int glthread_lock_lock (gl_lock_t *lock); 315 extern int glthread_lock_unlock (gl_lock_t *lock); 316 extern int glthread_lock_destroy (gl_lock_t *lock); 317 318 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 319 320 /* It is impossible to implement read-write locks using plain locks, without 321 introducing an extra thread dedicated to managing read-write locks. 322 Therefore here we need to use the low-level Event type. */ 323 324 typedef struct 325 { 326 HANDLE *array; /* array of waiting threads, each represented by an event */ 327 unsigned int count; /* number of waiting threads */ 328 unsigned int alloc; /* length of allocated array */ 329 unsigned int offset; /* index of first waiting thread in array */ 330 } 331 gl_waitqueue_t; 332 typedef struct 333 { 334 gl_spinlock_t guard; /* protects the initialization */ 335 CRITICAL_SECTION lock; /* protects the remaining fields */ 336 gl_waitqueue_t waiting_readers; /* waiting readers */ 337 gl_waitqueue_t waiting_writers; /* waiting writers */ 338 int runcount; /* number of readers running, or -1 when a writer runs */ 339 } 340 gl_rwlock_t; 341 # define gl_rwlock_define(STORAGECLASS, NAME) \ 342 STORAGECLASS gl_rwlock_t NAME; 343 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \ 344 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer; 345 # define gl_rwlock_initializer \ 346 { { 0, -1 } } 347 # define glthread_rwlock_init(LOCK) \ 348 (glthread_rwlock_init_func (LOCK), 0) 349 extern void glthread_rwlock_init_func (gl_rwlock_t *lock); 350 extern int glthread_rwlock_rdlock (gl_rwlock_t *lock); 351 extern int glthread_rwlock_wrlock (gl_rwlock_t *lock); 352 extern int glthread_rwlock_unlock (gl_rwlock_t *lock); 353 extern int glthread_rwlock_destroy (gl_rwlock_t *lock); 354 355 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 356 357 /* The Win32 documentation says that CRITICAL_SECTION already implements a 358 recursive lock. But we need not rely on it: It's easy to implement a 359 recursive lock without this assumption. */ 360 361 typedef struct 362 { 363 gl_spinlock_t guard; /* protects the initialization */ 364 DWORD owner; 365 unsigned long depth; 366 CRITICAL_SECTION lock; 367 } 368 gl_recursive_lock_t; 369 # define gl_recursive_lock_define(STORAGECLASS, NAME) \ 370 STORAGECLASS gl_recursive_lock_t NAME; 371 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \ 372 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer; 373 # define gl_recursive_lock_initializer \ 374 { { 0, -1 }, 0, 0 } 375 # define glthread_recursive_lock_init(LOCK) \ 376 (glthread_recursive_lock_init_func (LOCK), 0) 377 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock); 378 extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock); 379 extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock); 380 extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock); 381 382 /* -------------------------- gl_once_t datatype -------------------------- */ 383 384 typedef struct 385 { 386 volatile int inited; 387 volatile long started; 388 CRITICAL_SECTION lock; 389 } 390 gl_once_t; 391 # define gl_once_define(STORAGECLASS, NAME) \ 392 STORAGECLASS gl_once_t NAME = { -1, -1 }; 393 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 394 (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0) 395 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void)); 396 397 # ifdef __cplusplus 398 } 399 # endif 400 401 #endif 402 403 /* ========================================================================= */ 404 405 #if !(USE_POSIX_THREADS || USE_WIN32_THREADS) 406 407 /* Provide dummy implementation if threads are not supported. */ 408 409 /* -------------------------- gl_lock_t datatype -------------------------- */ 410 411 typedef int gl_lock_t; 412 # define gl_lock_define(STORAGECLASS, NAME) 413 # define gl_lock_define_initialized(STORAGECLASS, NAME) 414 # define glthread_lock_init(NAME) 0 415 # define glthread_lock_lock(NAME) 0 416 # define glthread_lock_unlock(NAME) 0 417 # define glthread_lock_destroy(NAME) 0 418 419 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 420 421 typedef int gl_rwlock_t; 422 # define gl_rwlock_define(STORAGECLASS, NAME) 423 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) 424 # define glthread_rwlock_init(NAME) 0 425 # define glthread_rwlock_rdlock(NAME) 0 426 # define glthread_rwlock_wrlock(NAME) 0 427 # define glthread_rwlock_unlock(NAME) 0 428 # define glthread_rwlock_destroy(NAME) 0 429 430 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 431 432 typedef int gl_recursive_lock_t; 433 # define gl_recursive_lock_define(STORAGECLASS, NAME) 434 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) 435 # define glthread_recursive_lock_init(NAME) 0 436 # define glthread_recursive_lock_lock(NAME) 0 437 # define glthread_recursive_lock_unlock(NAME) 0 438 # define glthread_recursive_lock_destroy(NAME) 0 439 440 /* -------------------------- gl_once_t datatype -------------------------- */ 441 442 typedef int gl_once_t; 443 # define gl_once_define(STORAGECLASS, NAME) \ 444 STORAGECLASS gl_once_t NAME = 0; 445 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \ 446 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0) 447 448 #endif 449 450 /* ========================================================================= */ 451 452 /* Macros with built-in error handling. */ 453 454 /* -------------------------- gl_lock_t datatype -------------------------- */ 455 456 #define gl_lock_init(NAME) \ 457 do \ 458 { \ 459 if (glthread_lock_init (&NAME)) \ 460 abort (); \ 461 } \ 462 while (0) 463 #define gl_lock_lock(NAME) \ 464 do \ 465 { \ 466 if (glthread_lock_lock (&NAME)) \ 467 abort (); \ 468 } \ 469 while (0) 470 #define gl_lock_unlock(NAME) \ 471 do \ 472 { \ 473 if (glthread_lock_unlock (&NAME)) \ 474 abort (); \ 475 } \ 476 while (0) 477 #define gl_lock_destroy(NAME) \ 478 do \ 479 { \ 480 if (glthread_lock_destroy (&NAME)) \ 481 abort (); \ 482 } \ 483 while (0) 484 485 /* ------------------------- gl_rwlock_t datatype ------------------------- */ 486 487 #define gl_rwlock_init(NAME) \ 488 do \ 489 { \ 490 if (glthread_rwlock_init (&NAME)) \ 491 abort (); \ 492 } \ 493 while (0) 494 #define gl_rwlock_rdlock(NAME) \ 495 do \ 496 { \ 497 if (glthread_rwlock_rdlock (&NAME)) \ 498 abort (); \ 499 } \ 500 while (0) 501 #define gl_rwlock_wrlock(NAME) \ 502 do \ 503 { \ 504 if (glthread_rwlock_wrlock (&NAME)) \ 505 abort (); \ 506 } \ 507 while (0) 508 #define gl_rwlock_unlock(NAME) \ 509 do \ 510 { \ 511 if (glthread_rwlock_unlock (&NAME)) \ 512 abort (); \ 513 } \ 514 while (0) 515 #define gl_rwlock_destroy(NAME) \ 516 do \ 517 { \ 518 if (glthread_rwlock_destroy (&NAME)) \ 519 abort (); \ 520 } \ 521 while (0) 522 523 /* --------------------- gl_recursive_lock_t datatype --------------------- */ 524 525 #define gl_recursive_lock_init(NAME) \ 526 do \ 527 { \ 528 if (glthread_recursive_lock_init (&NAME)) \ 529 abort (); \ 530 } \ 531 while (0) 532 #define gl_recursive_lock_lock(NAME) \ 533 do \ 534 { \ 535 if (glthread_recursive_lock_lock (&NAME)) \ 536 abort (); \ 537 } \ 538 while (0) 539 #define gl_recursive_lock_unlock(NAME) \ 540 do \ 541 { \ 542 if (glthread_recursive_lock_unlock (&NAME)) \ 543 abort (); \ 544 } \ 545 while (0) 546 #define gl_recursive_lock_destroy(NAME) \ 547 do \ 548 { \ 549 if (glthread_recursive_lock_destroy (&NAME)) \ 550 abort (); \ 551 } \ 552 while (0) 553 554 /* -------------------------- gl_once_t datatype -------------------------- */ 555 556 #define gl_once(NAME, INITFUNCTION) \ 557 do \ 558 { \ 559 if (glthread_once (&NAME, INITFUNCTION)) \ 560 abort (); \ 561 } \ 562 while (0) 563 564 /* ========================================================================= */ 565 566 #endif /* _LOCK_H */ 567