Home | History | Annotate | Download | only in glthread
      1 /* Locking in multithreaded situations.
      2    Copyright (C) 2005-2012 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 3, 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, see <http://www.gnu.org/licenses/>.  */
     16 
     17 /* Written by Bruno Haible <bruno (at) clisp.org>, 2005.
     18    Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
     19    gthr-win32.h.  */
     20 
     21 /* This file contains locking primitives for use with a given thread library.
     22    It does not contain primitives for creating threads or for other
     23    synchronization primitives.
     24 
     25    Normal (non-recursive) locks:
     26      Type:                gl_lock_t
     27      Declaration:         gl_lock_define(extern, name)
     28      Initializer:         gl_lock_define_initialized(, name)
     29      Initialization:      gl_lock_init (name);
     30      Taking the lock:     gl_lock_lock (name);
     31      Releasing the lock:  gl_lock_unlock (name);
     32      De-initialization:   gl_lock_destroy (name);
     33    Equivalent functions with control of error handling:
     34      Initialization:      err = glthread_lock_init (&name);
     35      Taking the lock:     err = glthread_lock_lock (&name);
     36      Releasing the lock:  err = glthread_lock_unlock (&name);
     37      De-initialization:   err = glthread_lock_destroy (&name);
     38 
     39    Read-Write (non-recursive) locks:
     40      Type:                gl_rwlock_t
     41      Declaration:         gl_rwlock_define(extern, name)
     42      Initializer:         gl_rwlock_define_initialized(, name)
     43      Initialization:      gl_rwlock_init (name);
     44      Taking the lock:     gl_rwlock_rdlock (name);
     45                           gl_rwlock_wrlock (name);
     46      Releasing the lock:  gl_rwlock_unlock (name);
     47      De-initialization:   gl_rwlock_destroy (name);
     48    Equivalent functions with control of error handling:
     49      Initialization:      err = glthread_rwlock_init (&name);
     50      Taking the lock:     err = glthread_rwlock_rdlock (&name);
     51                           err = glthread_rwlock_wrlock (&name);
     52      Releasing the lock:  err = glthread_rwlock_unlock (&name);
     53      De-initialization:   err = glthread_rwlock_destroy (&name);
     54 
     55    Recursive locks:
     56      Type:                gl_recursive_lock_t
     57      Declaration:         gl_recursive_lock_define(extern, name)
     58      Initializer:         gl_recursive_lock_define_initialized(, name)
     59      Initialization:      gl_recursive_lock_init (name);
     60      Taking the lock:     gl_recursive_lock_lock (name);
     61      Releasing the lock:  gl_recursive_lock_unlock (name);
     62      De-initialization:   gl_recursive_lock_destroy (name);
     63    Equivalent functions with control of error handling:
     64      Initialization:      err = glthread_recursive_lock_init (&name);
     65      Taking the lock:     err = glthread_recursive_lock_lock (&name);
     66      Releasing the lock:  err = glthread_recursive_lock_unlock (&name);
     67      De-initialization:   err = glthread_recursive_lock_destroy (&name);
     68 
     69   Once-only execution:
     70      Type:                gl_once_t
     71      Initializer:         gl_once_define(extern, name)
     72      Execution:           gl_once (name, initfunction);
     73    Equivalent functions with control of error handling:
     74      Execution:           err = glthread_once (&name, initfunction);
     75 */
     76 
     77 
     78 #ifndef _LOCK_H
     79 #define _LOCK_H
     80 
     81 #include <errno.h>
     82 #include <stdlib.h>
     83 
     84 /* ========================================================================= */
     85 
     86 #if USE_POSIX_THREADS
     87 
     88 /* Use the POSIX threads library.  */
     89 
     90 # include <pthread.h>
     91 
     92 # ifdef __cplusplus
     93 extern "C" {
     94 # endif
     95 
     96 # if PTHREAD_IN_USE_DETECTION_HARD
     97 
     98 /* The pthread_in_use() detection needs to be done at runtime.  */
     99 #  define pthread_in_use() \
    100      glthread_in_use ()
    101 extern int glthread_in_use (void);
    102 
    103 # endif
    104 
    105 # if USE_POSIX_THREADS_WEAK
    106 
    107 /* Use weak references to the POSIX threads library.  */
    108 
    109 /* Weak references avoid dragging in external libraries if the other parts
    110    of the program don't use them.  Here we use them, because we don't want
    111    every program that uses libintl to depend on libpthread.  This assumes
    112    that libpthread would not be loaded after libintl; i.e. if libintl is
    113    loaded first, by an executable that does not depend on libpthread, and
    114    then a module is dynamically loaded that depends on libpthread, libintl
    115    will not be multithread-safe.  */
    116 
    117 /* The way to test at runtime whether libpthread is present is to test
    118    whether a function pointer's value, such as &pthread_mutex_init, is
    119    non-NULL.  However, some versions of GCC have a bug through which, in
    120    PIC mode, &foo != NULL always evaluates to true if there is a direct
    121    call to foo(...) in the same function.  To avoid this, we test the
    122    address of a function in libpthread that we don't use.  */
    123 
    124 #  pragma weak pthread_mutex_init
    125 #  pragma weak pthread_mutex_lock
    126 #  pragma weak pthread_mutex_unlock
    127 #  pragma weak pthread_mutex_destroy
    128 #  pragma weak pthread_rwlock_init
    129 #  pragma weak pthread_rwlock_rdlock
    130 #  pragma weak pthread_rwlock_wrlock
    131 #  pragma weak pthread_rwlock_unlock
    132 #  pragma weak pthread_rwlock_destroy
    133 #  pragma weak pthread_once
    134 #  pragma weak pthread_cond_init
    135 #  pragma weak pthread_cond_wait
    136 #  pragma weak pthread_cond_signal
    137 #  pragma weak pthread_cond_broadcast
    138 #  pragma weak pthread_cond_destroy
    139 #  pragma weak pthread_mutexattr_init
    140 #  pragma weak pthread_mutexattr_settype
    141 #  pragma weak pthread_mutexattr_destroy
    142 #  ifndef pthread_self
    143 #   pragma weak pthread_self
    144 #  endif
    145 
    146 #  if !PTHREAD_IN_USE_DETECTION_HARD
    147 #   pragma weak pthread_cancel
    148 #   define pthread_in_use() (pthread_cancel != NULL)
    149 #  endif
    150 
    151 # else
    152 
    153 #  if !PTHREAD_IN_USE_DETECTION_HARD
    154 #   define pthread_in_use() 1
    155 #  endif
    156 
    157 # endif
    158 
    159 /* -------------------------- gl_lock_t datatype -------------------------- */
    160 
    161 typedef pthread_mutex_t gl_lock_t;
    162 # define gl_lock_define(STORAGECLASS, NAME) \
    163     STORAGECLASS pthread_mutex_t NAME;
    164 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
    165     STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
    166 # define gl_lock_initializer \
    167     PTHREAD_MUTEX_INITIALIZER
    168 # define glthread_lock_init(LOCK) \
    169     (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
    170 # define glthread_lock_lock(LOCK) \
    171     (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
    172 # define glthread_lock_unlock(LOCK) \
    173     (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
    174 # define glthread_lock_destroy(LOCK) \
    175     (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
    176 
    177 /* ------------------------- gl_rwlock_t datatype ------------------------- */
    178 
    179 # if HAVE_PTHREAD_RWLOCK
    180 
    181 #  ifdef PTHREAD_RWLOCK_INITIALIZER
    182 
    183 typedef pthread_rwlock_t gl_rwlock_t;
    184 #   define gl_rwlock_define(STORAGECLASS, NAME) \
    185       STORAGECLASS pthread_rwlock_t NAME;
    186 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
    187       STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
    188 #   define gl_rwlock_initializer \
    189       PTHREAD_RWLOCK_INITIALIZER
    190 #   define glthread_rwlock_init(LOCK) \
    191       (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
    192 #   define glthread_rwlock_rdlock(LOCK) \
    193       (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
    194 #   define glthread_rwlock_wrlock(LOCK) \
    195       (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
    196 #   define glthread_rwlock_unlock(LOCK) \
    197       (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
    198 #   define glthread_rwlock_destroy(LOCK) \
    199       (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
    200 
    201 #  else
    202 
    203 typedef struct
    204         {
    205           int initialized;
    206           pthread_mutex_t guard;   /* protects the initialization */
    207           pthread_rwlock_t rwlock; /* read-write lock */
    208         }
    209         gl_rwlock_t;
    210 #   define gl_rwlock_define(STORAGECLASS, NAME) \
    211       STORAGECLASS gl_rwlock_t NAME;
    212 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
    213       STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
    214 #   define gl_rwlock_initializer \
    215       { 0, PTHREAD_MUTEX_INITIALIZER }
    216 #   define glthread_rwlock_init(LOCK) \
    217       (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
    218 #   define glthread_rwlock_rdlock(LOCK) \
    219       (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
    220 #   define glthread_rwlock_wrlock(LOCK) \
    221       (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
    222 #   define glthread_rwlock_unlock(LOCK) \
    223       (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
    224 #   define glthread_rwlock_destroy(LOCK) \
    225       (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
    226 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
    227 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
    228 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
    229 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
    230 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
    231 
    232 #  endif
    233 
    234 # else
    235 
    236 typedef struct
    237         {
    238           pthread_mutex_t lock; /* protects the remaining fields */
    239           pthread_cond_t waiting_readers; /* waiting readers */
    240           pthread_cond_t waiting_writers; /* waiting writers */
    241           unsigned int waiting_writers_count; /* number of waiting writers */
    242           int runcount; /* number of readers running, or -1 when a writer runs */
    243         }
    244         gl_rwlock_t;
    245 # define gl_rwlock_define(STORAGECLASS, NAME) \
    246     STORAGECLASS gl_rwlock_t NAME;
    247 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
    248     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
    249 # define gl_rwlock_initializer \
    250     { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
    251 # define glthread_rwlock_init(LOCK) \
    252     (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
    253 # define glthread_rwlock_rdlock(LOCK) \
    254     (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
    255 # define glthread_rwlock_wrlock(LOCK) \
    256     (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
    257 # define glthread_rwlock_unlock(LOCK) \
    258     (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
    259 # define glthread_rwlock_destroy(LOCK) \
    260     (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
    261 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
    262 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
    263 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
    264 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
    265 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
    266 
    267 # endif
    268 
    269 /* --------------------- gl_recursive_lock_t datatype --------------------- */
    270 
    271 # if HAVE_PTHREAD_MUTEX_RECURSIVE
    272 
    273 #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
    274 
    275 typedef pthread_mutex_t gl_recursive_lock_t;
    276 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
    277       STORAGECLASS pthread_mutex_t NAME;
    278 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
    279       STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
    280 #   ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
    281 #    define gl_recursive_lock_initializer \
    282        PTHREAD_RECURSIVE_MUTEX_INITIALIZER
    283 #   else
    284 #    define gl_recursive_lock_initializer \
    285        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
    286 #   endif
    287 #   define glthread_recursive_lock_init(LOCK) \
    288       (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
    289 #   define glthread_recursive_lock_lock(LOCK) \
    290       (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
    291 #   define glthread_recursive_lock_unlock(LOCK) \
    292       (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
    293 #   define glthread_recursive_lock_destroy(LOCK) \
    294       (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
    295 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
    296 
    297 #  else
    298 
    299 typedef struct
    300         {
    301           pthread_mutex_t recmutex; /* recursive mutex */
    302           pthread_mutex_t guard;    /* protects the initialization */
    303           int initialized;
    304         }
    305         gl_recursive_lock_t;
    306 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
    307       STORAGECLASS gl_recursive_lock_t NAME;
    308 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
    309       STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
    310 #   define gl_recursive_lock_initializer \
    311       { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
    312 #   define glthread_recursive_lock_init(LOCK) \
    313       (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
    314 #   define glthread_recursive_lock_lock(LOCK) \
    315       (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
    316 #   define glthread_recursive_lock_unlock(LOCK) \
    317       (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
    318 #   define glthread_recursive_lock_destroy(LOCK) \
    319       (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
    320 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
    321 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
    322 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
    323 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
    324 
    325 #  endif
    326 
    327 # else
    328 
    329 /* Old versions of POSIX threads on Solaris did not have recursive locks.
    330    We have to implement them ourselves.  */
    331 
    332 typedef struct
    333         {
    334           pthread_mutex_t mutex;
    335           pthread_t owner;
    336           unsigned long depth;
    337         }
    338         gl_recursive_lock_t;
    339 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
    340      STORAGECLASS gl_recursive_lock_t NAME;
    341 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
    342      STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
    343 #  define gl_recursive_lock_initializer \
    344      { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
    345 #  define glthread_recursive_lock_init(LOCK) \
    346      (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
    347 #  define glthread_recursive_lock_lock(LOCK) \
    348      (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
    349 #  define glthread_recursive_lock_unlock(LOCK) \
    350      (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
    351 #  define glthread_recursive_lock_destroy(LOCK) \
    352      (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
    353 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
    354 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
    355 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
    356 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
    357 
    358 # endif
    359 
    360 /* -------------------------- gl_once_t datatype -------------------------- */
    361 
    362 typedef pthread_once_t gl_once_t;
    363 # define gl_once_define(STORAGECLASS, NAME) \
    364     STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
    365 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
    366     (pthread_in_use ()                                                         \
    367      ? pthread_once (ONCE_CONTROL, INITFUNCTION)                               \
    368      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
    369 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
    370 
    371 # ifdef __cplusplus
    372 }
    373 # endif
    374 
    375 #endif
    376 
    377 /* ========================================================================= */
    378 
    379 #if USE_PTH_THREADS
    380 
    381 /* Use the GNU Pth threads library.  */
    382 
    383 # include <pth.h>
    384 
    385 # ifdef __cplusplus
    386 extern "C" {
    387 # endif
    388 
    389 # if USE_PTH_THREADS_WEAK
    390 
    391 /* Use weak references to the GNU Pth threads library.  */
    392 
    393 #  pragma weak pth_mutex_init
    394 #  pragma weak pth_mutex_acquire
    395 #  pragma weak pth_mutex_release
    396 #  pragma weak pth_rwlock_init
    397 #  pragma weak pth_rwlock_acquire
    398 #  pragma weak pth_rwlock_release
    399 #  pragma weak pth_once
    400 
    401 #  pragma weak pth_cancel
    402 #  define pth_in_use() (pth_cancel != NULL)
    403 
    404 # else
    405 
    406 #  define pth_in_use() 1
    407 
    408 # endif
    409 
    410 /* -------------------------- gl_lock_t datatype -------------------------- */
    411 
    412 typedef pth_mutex_t gl_lock_t;
    413 # define gl_lock_define(STORAGECLASS, NAME) \
    414     STORAGECLASS pth_mutex_t NAME;
    415 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
    416     STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
    417 # define gl_lock_initializer \
    418     PTH_MUTEX_INIT
    419 # define glthread_lock_init(LOCK) \
    420     (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
    421 # define glthread_lock_lock(LOCK) \
    422     (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
    423 # define glthread_lock_unlock(LOCK) \
    424     (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
    425 # define glthread_lock_destroy(LOCK) \
    426     ((void)(LOCK), 0)
    427 
    428 /* ------------------------- gl_rwlock_t datatype ------------------------- */
    429 
    430 typedef pth_rwlock_t gl_rwlock_t;
    431 #  define gl_rwlock_define(STORAGECLASS, NAME) \
    432      STORAGECLASS pth_rwlock_t NAME;
    433 #  define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
    434      STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
    435 #  define gl_rwlock_initializer \
    436      PTH_RWLOCK_INIT
    437 #  define glthread_rwlock_init(LOCK) \
    438      (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0)
    439 #  define glthread_rwlock_rdlock(LOCK) \
    440      (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0)
    441 #  define glthread_rwlock_wrlock(LOCK) \
    442      (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0)
    443 #  define glthread_rwlock_unlock(LOCK) \
    444      (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0)
    445 #  define glthread_rwlock_destroy(LOCK) \
    446      ((void)(LOCK), 0)
    447 
    448 /* --------------------- gl_recursive_lock_t datatype --------------------- */
    449 
    450 /* In Pth, mutexes are recursive by default.  */
    451 typedef pth_mutex_t gl_recursive_lock_t;
    452 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
    453      STORAGECLASS pth_mutex_t NAME;
    454 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
    455      STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
    456 #  define gl_recursive_lock_initializer \
    457      PTH_MUTEX_INIT
    458 #  define glthread_recursive_lock_init(LOCK) \
    459      (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
    460 #  define glthread_recursive_lock_lock(LOCK) \
    461      (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
    462 #  define glthread_recursive_lock_unlock(LOCK) \
    463      (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
    464 #  define glthread_recursive_lock_destroy(LOCK) \
    465      ((void)(LOCK), 0)
    466 
    467 /* -------------------------- gl_once_t datatype -------------------------- */
    468 
    469 typedef pth_once_t gl_once_t;
    470 # define gl_once_define(STORAGECLASS, NAME) \
    471     STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
    472 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
    473     (pth_in_use ()                                                             \
    474      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
    475      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
    476 extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void));
    477 extern int glthread_once_singlethreaded (pth_once_t *once_control);
    478 
    479 # ifdef __cplusplus
    480 }
    481 # endif
    482 
    483 #endif
    484 
    485 /* ========================================================================= */
    486 
    487 #if USE_SOLARIS_THREADS
    488 
    489 /* Use the old Solaris threads library.  */
    490 
    491 # include <thread.h>
    492 # include <synch.h>
    493 
    494 # ifdef __cplusplus
    495 extern "C" {
    496 # endif
    497 
    498 # if USE_SOLARIS_THREADS_WEAK
    499 
    500 /* Use weak references to the old Solaris threads library.  */
    501 
    502 #  pragma weak mutex_init
    503 #  pragma weak mutex_lock
    504 #  pragma weak mutex_unlock
    505 #  pragma weak mutex_destroy
    506 #  pragma weak rwlock_init
    507 #  pragma weak rw_rdlock
    508 #  pragma weak rw_wrlock
    509 #  pragma weak rw_unlock
    510 #  pragma weak rwlock_destroy
    511 #  pragma weak thr_self
    512 
    513 #  pragma weak thr_suspend
    514 #  define thread_in_use() (thr_suspend != NULL)
    515 
    516 # else
    517 
    518 #  define thread_in_use() 1
    519 
    520 # endif
    521 
    522 /* -------------------------- gl_lock_t datatype -------------------------- */
    523 
    524 typedef mutex_t gl_lock_t;
    525 # define gl_lock_define(STORAGECLASS, NAME) \
    526     STORAGECLASS mutex_t NAME;
    527 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
    528     STORAGECLASS mutex_t NAME = gl_lock_initializer;
    529 # define gl_lock_initializer \
    530     DEFAULTMUTEX
    531 # define glthread_lock_init(LOCK) \
    532     (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
    533 # define glthread_lock_lock(LOCK) \
    534     (thread_in_use () ? mutex_lock (LOCK) : 0)
    535 # define glthread_lock_unlock(LOCK) \
    536     (thread_in_use () ? mutex_unlock (LOCK) : 0)
    537 # define glthread_lock_destroy(LOCK) \
    538     (thread_in_use () ? mutex_destroy (LOCK) : 0)
    539 
    540 /* ------------------------- gl_rwlock_t datatype ------------------------- */
    541 
    542 typedef rwlock_t gl_rwlock_t;
    543 # define gl_rwlock_define(STORAGECLASS, NAME) \
    544     STORAGECLASS rwlock_t NAME;
    545 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
    546     STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
    547 # define gl_rwlock_initializer \
    548     DEFAULTRWLOCK
    549 # define glthread_rwlock_init(LOCK) \
    550     (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
    551 # define glthread_rwlock_rdlock(LOCK) \
    552     (thread_in_use () ? rw_rdlock (LOCK) : 0)
    553 # define glthread_rwlock_wrlock(LOCK) \
    554     (thread_in_use () ? rw_wrlock (LOCK) : 0)
    555 # define glthread_rwlock_unlock(LOCK) \
    556     (thread_in_use () ? rw_unlock (LOCK) : 0)
    557 # define glthread_rwlock_destroy(LOCK) \
    558     (thread_in_use () ? rwlock_destroy (LOCK) : 0)
    559 
    560 /* --------------------- gl_recursive_lock_t datatype --------------------- */
    561 
    562 /* Old Solaris threads did not have recursive locks.
    563    We have to implement them ourselves.  */
    564 
    565 typedef struct
    566         {
    567           mutex_t mutex;
    568           thread_t owner;
    569           unsigned long depth;
    570         }
    571         gl_recursive_lock_t;
    572 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
    573     STORAGECLASS gl_recursive_lock_t NAME;
    574 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
    575     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
    576 # define gl_recursive_lock_initializer \
    577     { DEFAULTMUTEX, (thread_t) 0, 0 }
    578 # define glthread_recursive_lock_init(LOCK) \
    579     (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
    580 # define glthread_recursive_lock_lock(LOCK) \
    581     (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
    582 # define glthread_recursive_lock_unlock(LOCK) \
    583     (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
    584 # define glthread_recursive_lock_destroy(LOCK) \
    585     (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
    586 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
    587 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
    588 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
    589 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
    590 
    591 /* -------------------------- gl_once_t datatype -------------------------- */
    592 
    593 typedef struct
    594         {
    595           volatile int inited;
    596           mutex_t mutex;
    597         }
    598         gl_once_t;
    599 # define gl_once_define(STORAGECLASS, NAME) \
    600     STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
    601 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
    602     (thread_in_use ()                                                          \
    603      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
    604      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
    605 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
    606 extern int glthread_once_singlethreaded (gl_once_t *once_control);
    607 
    608 # ifdef __cplusplus
    609 }
    610 # endif
    611 
    612 #endif
    613 
    614 /* ========================================================================= */
    615 
    616 #if USE_WINDOWS_THREADS
    617 
    618 # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
    619 # include <windows.h>
    620 
    621 # ifdef __cplusplus
    622 extern "C" {
    623 # endif
    624 
    625 /* We can use CRITICAL_SECTION directly, rather than the native Windows Event,
    626    Mutex, 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 
    636 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
    637 
    638 /* -------------------------- gl_lock_t datatype -------------------------- */
    639 
    640 typedef 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)
    660 extern void glthread_lock_init_func (gl_lock_t *lock);
    661 extern int glthread_lock_lock_func (gl_lock_t *lock);
    662 extern int glthread_lock_unlock_func (gl_lock_t *lock);
    663 extern 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 
    671 typedef 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;
    679 typedef 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)
    704 extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
    705 extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock);
    706 extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock);
    707 extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock);
    708 extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock);
    709 
    710 /* --------------------- gl_recursive_lock_t datatype --------------------- */
    711 
    712 /* The native Windows documentation says that CRITICAL_SECTION already
    713    implements a recursive lock.  But we need not rely on it: It's easy to
    714    implement a recursive lock without this assumption.  */
    715 
    716 typedef 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)
    738 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
    739 extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock);
    740 extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock);
    741 extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock);
    742 
    743 /* -------------------------- gl_once_t datatype -------------------------- */
    744 
    745 typedef 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)
    756 extern 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_WINDOWS_THREADS)
    767 
    768 /* Provide dummy implementation if threads are not supported.  */
    769 
    770 /* -------------------------- gl_lock_t datatype -------------------------- */
    771 
    772 typedef 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 
    782 typedef 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 
    793 typedef 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 
    803 typedef 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