(root)/
findutils-4.9.0/
gl/
lib/
glthread/
lock.h
       1  /* Locking in multithreaded situations.
       2     Copyright (C) 2005-2022 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     This file 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, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Bruno Haible <bruno@clisp.org>, 2005.
      18     Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h.  */
      19  
      20  /* This file contains locking primitives for use with a given thread library.
      21     It does not contain primitives for creating threads or for other
      22     synchronization primitives.
      23  
      24     Normal (non-recursive) locks:
      25       Type:                gl_lock_t
      26       Declaration:         gl_lock_define(extern, name)
      27       Initializer:         gl_lock_define_initialized(, name)
      28       Initialization:      gl_lock_init (name);
      29       Taking the lock:     gl_lock_lock (name);
      30       Releasing the lock:  gl_lock_unlock (name);
      31       De-initialization:   gl_lock_destroy (name);
      32     Equivalent functions with control of error handling:
      33       Initialization:      err = glthread_lock_init (&name);
      34       Taking the lock:     err = glthread_lock_lock (&name);
      35       Releasing the lock:  err = glthread_lock_unlock (&name);
      36       De-initialization:   err = glthread_lock_destroy (&name);
      37  
      38     Read-Write (non-recursive) locks:
      39       Type:                gl_rwlock_t
      40       Declaration:         gl_rwlock_define(extern, name)
      41       Initializer:         gl_rwlock_define_initialized(, name)
      42       Initialization:      gl_rwlock_init (name);
      43       Taking the lock:     gl_rwlock_rdlock (name);
      44                            gl_rwlock_wrlock (name);
      45       Releasing the lock:  gl_rwlock_unlock (name);
      46       De-initialization:   gl_rwlock_destroy (name);
      47     Equivalent functions with control of error handling:
      48       Initialization:      err = glthread_rwlock_init (&name);
      49       Taking the lock:     err = glthread_rwlock_rdlock (&name);
      50                            err = glthread_rwlock_wrlock (&name);
      51       Releasing the lock:  err = glthread_rwlock_unlock (&name);
      52       De-initialization:   err = glthread_rwlock_destroy (&name);
      53  
      54     Recursive locks:
      55       Type:                gl_recursive_lock_t
      56       Declaration:         gl_recursive_lock_define(extern, name)
      57       Initializer:         gl_recursive_lock_define_initialized(, name)
      58       Initialization:      gl_recursive_lock_init (name);
      59       Taking the lock:     gl_recursive_lock_lock (name);
      60       Releasing the lock:  gl_recursive_lock_unlock (name);
      61       De-initialization:   gl_recursive_lock_destroy (name);
      62     Equivalent functions with control of error handling:
      63       Initialization:      err = glthread_recursive_lock_init (&name);
      64       Taking the lock:     err = glthread_recursive_lock_lock (&name);
      65       Releasing the lock:  err = glthread_recursive_lock_unlock (&name);
      66       De-initialization:   err = glthread_recursive_lock_destroy (&name);
      67  
      68    Once-only execution:
      69       Type:                gl_once_t
      70       Initializer:         gl_once_define(extern, name)
      71       Execution:           gl_once (name, initfunction);
      72     Equivalent functions with control of error handling:
      73       Execution:           err = glthread_once (&name, initfunction);
      74  */
      75  
      76  
      77  #ifndef _LOCK_H
      78  #define _LOCK_H
      79  
      80  #include <errno.h>
      81  #include <stdlib.h>
      82  
      83  #if !defined c11_threads_in_use
      84  # if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
      85  #  define c11_threads_in_use() 1
      86  # elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
      87  #  include <threads.h>
      88  #  pragma weak thrd_exit
      89  #  define c11_threads_in_use() (thrd_exit != NULL)
      90  # else
      91  #  define c11_threads_in_use() 0
      92  # endif
      93  #endif
      94  
      95  /* ========================================================================= */
      96  
      97  #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
      98  
      99  /* Use the ISO C threads library.  */
     100  
     101  # include <threads.h>
     102  
     103  # ifdef __cplusplus
     104  extern "C" {
     105  # endif
     106  
     107  /* -------------------------- gl_lock_t datatype -------------------------- */
     108  
     109  typedef struct
     110          {
     111            int volatile init_needed;
     112            once_flag init_once;
     113            void (*init_func) (void);
     114            mtx_t mutex;
     115          }
     116          gl_lock_t;
     117  # define gl_lock_define(STORAGECLASS, NAME) \
     118      STORAGECLASS gl_lock_t NAME;
     119  # define gl_lock_define_initialized(STORAGECLASS, NAME) \
     120      static void _atomic_init_##NAME (void);       \
     121      STORAGECLASS gl_lock_t NAME =                 \
     122        { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
     123      static void _atomic_init_##NAME (void)        \
     124      {                                             \
     125        if (glthread_lock_init (&(NAME)))           \
     126          abort ();                                 \
     127      }
     128  extern int glthread_lock_init (gl_lock_t *lock);
     129  extern int glthread_lock_lock (gl_lock_t *lock);
     130  extern int glthread_lock_unlock (gl_lock_t *lock);
     131  extern int glthread_lock_destroy (gl_lock_t *lock);
     132  
     133  /* ------------------------- gl_rwlock_t datatype ------------------------- */
     134  
     135  typedef struct
     136          {
     137            int volatile init_needed;
     138            once_flag init_once;
     139            void (*init_func) (void);
     140            mtx_t lock; /* protects the remaining fields */
     141            cnd_t waiting_readers; /* waiting readers */
     142            cnd_t waiting_writers; /* waiting writers */
     143            unsigned int waiting_writers_count; /* number of waiting writers */
     144            int runcount; /* number of readers running, or -1 when a writer runs */
     145          }
     146          gl_rwlock_t;
     147  # define gl_rwlock_define(STORAGECLASS, NAME) \
     148      STORAGECLASS gl_rwlock_t NAME;
     149  # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
     150      static void _atomic_init_##NAME (void);       \
     151      STORAGECLASS gl_rwlock_t NAME =               \
     152        { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
     153      static void _atomic_init_##NAME (void)        \
     154      {                                             \
     155        if (glthread_rwlock_init (&(NAME)))         \
     156          abort ();                                 \
     157      }
     158  extern int glthread_rwlock_init (gl_rwlock_t *lock);
     159  extern int glthread_rwlock_rdlock (gl_rwlock_t *lock);
     160  extern int glthread_rwlock_wrlock (gl_rwlock_t *lock);
     161  extern int glthread_rwlock_unlock (gl_rwlock_t *lock);
     162  extern int glthread_rwlock_destroy (gl_rwlock_t *lock);
     163  
     164  /* --------------------- gl_recursive_lock_t datatype --------------------- */
     165  
     166  typedef struct
     167          {
     168            int volatile init_needed;
     169            once_flag init_once;
     170            void (*init_func) (void);
     171            mtx_t mutex;
     172          }
     173          gl_recursive_lock_t;
     174  # define gl_recursive_lock_define(STORAGECLASS, NAME) \
     175      STORAGECLASS gl_recursive_lock_t NAME;
     176  # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
     177      static void _atomic_init_##NAME (void);       \
     178      STORAGECLASS gl_recursive_lock_t NAME =       \
     179        { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
     180      static void _atomic_init_##NAME (void)        \
     181      {                                             \
     182        if (glthread_recursive_lock_init (&(NAME))) \
     183          abort ();                                 \
     184      }
     185  extern int glthread_recursive_lock_init (gl_recursive_lock_t *lock);
     186  extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
     187  extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
     188  extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
     189  
     190  /* -------------------------- gl_once_t datatype -------------------------- */
     191  
     192  typedef once_flag gl_once_t;
     193  # define gl_once_define(STORAGECLASS, NAME) \
     194      STORAGECLASS once_flag NAME = ONCE_FLAG_INIT;
     195  # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
     196      (call_once (ONCE_CONTROL, INITFUNCTION), 0)
     197  
     198  # ifdef __cplusplus
     199  }
     200  # endif
     201  
     202  #endif
     203  
     204  /* ========================================================================= */
     205  
     206  #if USE_POSIX_THREADS
     207  
     208  /* Use the POSIX threads library.  */
     209  
     210  # include <pthread.h>
     211  
     212  # ifdef __cplusplus
     213  extern "C" {
     214  # endif
     215  
     216  # if PTHREAD_IN_USE_DETECTION_HARD
     217  
     218  /* The pthread_in_use() detection needs to be done at runtime.  */
     219  #  define pthread_in_use() \
     220       glthread_in_use ()
     221  extern int glthread_in_use (void);
     222  
     223  # endif
     224  
     225  # if USE_POSIX_THREADS_WEAK
     226  
     227  /* Use weak references to the POSIX threads library.  */
     228  
     229  /* Weak references avoid dragging in external libraries if the other parts
     230     of the program don't use them.  Here we use them, because we don't want
     231     every program that uses libintl to depend on libpthread.  This assumes
     232     that libpthread would not be loaded after libintl; i.e. if libintl is
     233     loaded first, by an executable that does not depend on libpthread, and
     234     then a module is dynamically loaded that depends on libpthread, libintl
     235     will not be multithread-safe.  */
     236  
     237  /* The way to test at runtime whether libpthread is present is to test
     238     whether a function pointer's value, such as &pthread_mutex_init, is
     239     non-NULL.  However, some versions of GCC have a bug through which, in
     240     PIC mode, &foo != NULL always evaluates to true if there is a direct
     241     call to foo(...) in the same function.  To avoid this, we test the
     242     address of a function in libpthread that we don't use.  */
     243  
     244  #  pragma weak pthread_mutex_init
     245  #  pragma weak pthread_mutex_lock
     246  #  pragma weak pthread_mutex_unlock
     247  #  pragma weak pthread_mutex_destroy
     248  #  pragma weak pthread_rwlock_init
     249  #  pragma weak pthread_rwlock_rdlock
     250  #  pragma weak pthread_rwlock_wrlock
     251  #  pragma weak pthread_rwlock_unlock
     252  #  pragma weak pthread_rwlock_destroy
     253  #  pragma weak pthread_once
     254  #  pragma weak pthread_cond_init
     255  #  pragma weak pthread_cond_wait
     256  #  pragma weak pthread_cond_signal
     257  #  pragma weak pthread_cond_broadcast
     258  #  pragma weak pthread_cond_destroy
     259  #  pragma weak pthread_mutexattr_init
     260  #  pragma weak pthread_mutexattr_settype
     261  #  pragma weak pthread_mutexattr_destroy
     262  #  pragma weak pthread_rwlockattr_init
     263  #  if __GNU_LIBRARY__ > 1
     264  #   pragma weak pthread_rwlockattr_setkind_np
     265  #  endif
     266  #  pragma weak pthread_rwlockattr_destroy
     267  #  ifndef pthread_self
     268  #   pragma weak pthread_self
     269  #  endif
     270  
     271  #  if !PTHREAD_IN_USE_DETECTION_HARD
     272      /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols
     273         can be used to determine whether libpthread is in use.  These are:
     274           pthread_mutexattr_gettype
     275           pthread_rwlockattr_destroy
     276           pthread_rwlockattr_init
     277       */
     278  #   pragma weak pthread_mutexattr_gettype
     279  #   define pthread_in_use() \
     280        (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
     281  #  endif
     282  
     283  # else
     284  
     285  #  if !PTHREAD_IN_USE_DETECTION_HARD
     286  #   define pthread_in_use() 1
     287  #  endif
     288  
     289  # endif
     290  
     291  /* -------------------------- gl_lock_t datatype -------------------------- */
     292  
     293  typedef pthread_mutex_t gl_lock_t;
     294  # define gl_lock_define(STORAGECLASS, NAME) \
     295      STORAGECLASS pthread_mutex_t NAME;
     296  # define gl_lock_define_initialized(STORAGECLASS, NAME) \
     297      STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
     298  # define gl_lock_initializer \
     299      PTHREAD_MUTEX_INITIALIZER
     300  # define glthread_lock_init(LOCK) \
     301      (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
     302  # define glthread_lock_lock(LOCK) \
     303      (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
     304  # define glthread_lock_unlock(LOCK) \
     305      (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
     306  # define glthread_lock_destroy(LOCK) \
     307      (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
     308  
     309  /* ------------------------- gl_rwlock_t datatype ------------------------- */
     310  
     311  # if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
     312  
     313  #  if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP
     314  
     315  typedef pthread_rwlock_t gl_rwlock_t;
     316  #   define gl_rwlock_define(STORAGECLASS, NAME) \
     317        STORAGECLASS pthread_rwlock_t NAME;
     318  #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
     319        STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
     320  #   if HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
     321  #    if defined PTHREAD_RWLOCK_INITIALIZER
     322  #     define gl_rwlock_initializer \
     323          PTHREAD_RWLOCK_INITIALIZER
     324  #    else
     325  #     define gl_rwlock_initializer \
     326          PTHREAD_RWLOCK_INITIALIZER_NP
     327  #    endif
     328  #    define glthread_rwlock_init(LOCK) \
     329         (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
     330  #   else /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
     331  #    define gl_rwlock_initializer \
     332         PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
     333  #    define glthread_rwlock_init(LOCK) \
     334         (pthread_in_use () ? glthread_rwlock_init_for_glibc (LOCK) : 0)
     335  extern int glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock);
     336  #   endif
     337  #   define glthread_rwlock_rdlock(LOCK) \
     338        (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
     339  #   define glthread_rwlock_wrlock(LOCK) \
     340        (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
     341  #   define glthread_rwlock_unlock(LOCK) \
     342        (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
     343  #   define glthread_rwlock_destroy(LOCK) \
     344        (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
     345  
     346  #  else
     347  
     348  typedef struct
     349          {
     350            int initialized;
     351            pthread_mutex_t guard;   /* protects the initialization */
     352            pthread_rwlock_t rwlock; /* read-write lock */
     353          }
     354          gl_rwlock_t;
     355  #   define gl_rwlock_define(STORAGECLASS, NAME) \
     356        STORAGECLASS gl_rwlock_t NAME;
     357  #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
     358        STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
     359  #   define gl_rwlock_initializer \
     360        { 0, PTHREAD_MUTEX_INITIALIZER }
     361  #   define glthread_rwlock_init(LOCK) \
     362        (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
     363  #   define glthread_rwlock_rdlock(LOCK) \
     364        (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
     365  #   define glthread_rwlock_wrlock(LOCK) \
     366        (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
     367  #   define glthread_rwlock_unlock(LOCK) \
     368        (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
     369  #   define glthread_rwlock_destroy(LOCK) \
     370        (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
     371  extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
     372  extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
     373  extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
     374  extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
     375  extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
     376  
     377  #  endif
     378  
     379  # else
     380  
     381  typedef struct
     382          {
     383            pthread_mutex_t lock; /* protects the remaining fields */
     384            pthread_cond_t waiting_readers; /* waiting readers */
     385            pthread_cond_t waiting_writers; /* waiting writers */
     386            unsigned int waiting_writers_count; /* number of waiting writers */
     387            int runcount; /* number of readers running, or -1 when a writer runs */
     388          }
     389          gl_rwlock_t;
     390  # define gl_rwlock_define(STORAGECLASS, NAME) \
     391      STORAGECLASS gl_rwlock_t NAME;
     392  # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
     393      STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
     394  # define gl_rwlock_initializer \
     395      { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
     396  # define glthread_rwlock_init(LOCK) \
     397      (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
     398  # define glthread_rwlock_rdlock(LOCK) \
     399      (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
     400  # define glthread_rwlock_wrlock(LOCK) \
     401      (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
     402  # define glthread_rwlock_unlock(LOCK) \
     403      (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
     404  # define glthread_rwlock_destroy(LOCK) \
     405      (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
     406  extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
     407  extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
     408  extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
     409  extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
     410  extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
     411  
     412  # endif
     413  
     414  /* --------------------- gl_recursive_lock_t datatype --------------------- */
     415  
     416  # if HAVE_PTHREAD_MUTEX_RECURSIVE
     417  
     418  #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
     419  
     420  typedef pthread_mutex_t gl_recursive_lock_t;
     421  #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
     422        STORAGECLASS pthread_mutex_t NAME;
     423  #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
     424        STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
     425  #   ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
     426  #    define gl_recursive_lock_initializer \
     427         PTHREAD_RECURSIVE_MUTEX_INITIALIZER
     428  #   else
     429  #    define gl_recursive_lock_initializer \
     430         PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
     431  #   endif
     432  #   define glthread_recursive_lock_init(LOCK) \
     433        (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
     434  #   define glthread_recursive_lock_lock(LOCK) \
     435        (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
     436  #   define glthread_recursive_lock_unlock(LOCK) \
     437        (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
     438  #   define glthread_recursive_lock_destroy(LOCK) \
     439        (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
     440  extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
     441  
     442  #  else
     443  
     444  typedef struct
     445          {
     446            pthread_mutex_t recmutex; /* recursive mutex */
     447            pthread_mutex_t guard;    /* protects the initialization */
     448            int initialized;
     449          }
     450          gl_recursive_lock_t;
     451  #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
     452        STORAGECLASS gl_recursive_lock_t NAME;
     453  #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
     454        STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
     455  #   define gl_recursive_lock_initializer \
     456        { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
     457  #   define glthread_recursive_lock_init(LOCK) \
     458        (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
     459  #   define glthread_recursive_lock_lock(LOCK) \
     460        (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
     461  #   define glthread_recursive_lock_unlock(LOCK) \
     462        (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
     463  #   define glthread_recursive_lock_destroy(LOCK) \
     464        (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
     465  extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
     466  extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
     467  extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
     468  extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
     469  
     470  #  endif
     471  
     472  # else
     473  
     474  /* Old versions of POSIX threads on Solaris did not have recursive locks.
     475     We have to implement them ourselves.  */
     476  
     477  typedef struct
     478          {
     479            pthread_mutex_t mutex;
     480            pthread_t owner;
     481            unsigned long depth;
     482          }
     483          gl_recursive_lock_t;
     484  #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
     485       STORAGECLASS gl_recursive_lock_t NAME;
     486  #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
     487       STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
     488  #  define gl_recursive_lock_initializer \
     489       { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
     490  #  define glthread_recursive_lock_init(LOCK) \
     491       (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
     492  #  define glthread_recursive_lock_lock(LOCK) \
     493       (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
     494  #  define glthread_recursive_lock_unlock(LOCK) \
     495       (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
     496  #  define glthread_recursive_lock_destroy(LOCK) \
     497       (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
     498  extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
     499  extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
     500  extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
     501  extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
     502  
     503  # endif
     504  
     505  /* -------------------------- gl_once_t datatype -------------------------- */
     506  
     507  typedef pthread_once_t gl_once_t;
     508  # define gl_once_define(STORAGECLASS, NAME) \
     509      STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
     510  # if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK
     511  #  define glthread_once(ONCE_CONTROL, INITFUNCTION) \
     512       (pthread_in_use ()                                                        \
     513        ? pthread_once (ONCE_CONTROL, INITFUNCTION)                              \
     514        : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
     515  # else
     516  #  define glthread_once(ONCE_CONTROL, INITFUNCTION) \
     517       (pthread_in_use ()                                                        \
     518        ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)               \
     519        : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
     520  extern int glthread_once_multithreaded (pthread_once_t *once_control,
     521                                          void (*init_function) (void));
     522  # endif
     523  extern int glthread_once_singlethreaded (pthread_once_t *once_control);
     524  
     525  # ifdef __cplusplus
     526  }
     527  # endif
     528  
     529  #endif
     530  
     531  /* ========================================================================= */
     532  
     533  #if USE_WINDOWS_THREADS
     534  
     535  # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
     536  # include <windows.h>
     537  
     538  # include "windows-mutex.h"
     539  # include "windows-rwlock.h"
     540  # include "windows-recmutex.h"
     541  # include "windows-once.h"
     542  
     543  # ifdef __cplusplus
     544  extern "C" {
     545  # endif
     546  
     547  /* We can use CRITICAL_SECTION directly, rather than the native Windows Event,
     548     Mutex, Semaphore types, because
     549       - we need only to synchronize inside a single process (address space),
     550         not inter-process locking,
     551       - we don't need to support trylock operations.  (TryEnterCriticalSection
     552         does not work on Windows 95/98/ME.  Packages that need trylock usually
     553         define their own mutex type.)  */
     554  
     555  /* There is no way to statically initialize a CRITICAL_SECTION.  It needs
     556     to be done lazily, once only.  For this we need spinlocks.  */
     557  
     558  /* -------------------------- gl_lock_t datatype -------------------------- */
     559  
     560  typedef glwthread_mutex_t gl_lock_t;
     561  # define gl_lock_define(STORAGECLASS, NAME) \
     562      STORAGECLASS gl_lock_t NAME;
     563  # define gl_lock_define_initialized(STORAGECLASS, NAME) \
     564      STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
     565  # define gl_lock_initializer \
     566      GLWTHREAD_MUTEX_INIT
     567  # define glthread_lock_init(LOCK) \
     568      (glwthread_mutex_init (LOCK), 0)
     569  # define glthread_lock_lock(LOCK) \
     570      glwthread_mutex_lock (LOCK)
     571  # define glthread_lock_unlock(LOCK) \
     572      glwthread_mutex_unlock (LOCK)
     573  # define glthread_lock_destroy(LOCK) \
     574      glwthread_mutex_destroy (LOCK)
     575  
     576  /* ------------------------- gl_rwlock_t datatype ------------------------- */
     577  
     578  typedef glwthread_rwlock_t gl_rwlock_t;
     579  # define gl_rwlock_define(STORAGECLASS, NAME) \
     580      STORAGECLASS gl_rwlock_t NAME;
     581  # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
     582      STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
     583  # define gl_rwlock_initializer \
     584      GLWTHREAD_RWLOCK_INIT
     585  # define glthread_rwlock_init(LOCK) \
     586      (glwthread_rwlock_init (LOCK), 0)
     587  # define glthread_rwlock_rdlock(LOCK) \
     588      glwthread_rwlock_rdlock (LOCK)
     589  # define glthread_rwlock_wrlock(LOCK) \
     590      glwthread_rwlock_wrlock (LOCK)
     591  # define glthread_rwlock_unlock(LOCK) \
     592      glwthread_rwlock_unlock (LOCK)
     593  # define glthread_rwlock_destroy(LOCK) \
     594      glwthread_rwlock_destroy (LOCK)
     595  
     596  /* --------------------- gl_recursive_lock_t datatype --------------------- */
     597  
     598  typedef glwthread_recmutex_t gl_recursive_lock_t;
     599  # define gl_recursive_lock_define(STORAGECLASS, NAME) \
     600      STORAGECLASS gl_recursive_lock_t NAME;
     601  # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
     602      STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
     603  # define gl_recursive_lock_initializer \
     604      GLWTHREAD_RECMUTEX_INIT
     605  # define glthread_recursive_lock_init(LOCK) \
     606      (glwthread_recmutex_init (LOCK), 0)
     607  # define glthread_recursive_lock_lock(LOCK) \
     608      glwthread_recmutex_lock (LOCK)
     609  # define glthread_recursive_lock_unlock(LOCK) \
     610      glwthread_recmutex_unlock (LOCK)
     611  # define glthread_recursive_lock_destroy(LOCK) \
     612      glwthread_recmutex_destroy (LOCK)
     613  
     614  /* -------------------------- gl_once_t datatype -------------------------- */
     615  
     616  typedef glwthread_once_t gl_once_t;
     617  # define gl_once_define(STORAGECLASS, NAME) \
     618      STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT;
     619  # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
     620      (glwthread_once (ONCE_CONTROL, INITFUNCTION), 0)
     621  
     622  # ifdef __cplusplus
     623  }
     624  # endif
     625  
     626  #endif
     627  
     628  /* ========================================================================= */
     629  
     630  #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
     631  
     632  /* Provide dummy implementation if threads are not supported.  */
     633  
     634  /* -------------------------- gl_lock_t datatype -------------------------- */
     635  
     636  typedef int gl_lock_t;
     637  # define gl_lock_define(STORAGECLASS, NAME)
     638  # define gl_lock_define_initialized(STORAGECLASS, NAME)
     639  # define glthread_lock_init(NAME) 0
     640  # define glthread_lock_lock(NAME) 0
     641  # define glthread_lock_unlock(NAME) 0
     642  # define glthread_lock_destroy(NAME) 0
     643  
     644  /* ------------------------- gl_rwlock_t datatype ------------------------- */
     645  
     646  typedef int gl_rwlock_t;
     647  # define gl_rwlock_define(STORAGECLASS, NAME)
     648  # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
     649  # define glthread_rwlock_init(NAME) 0
     650  # define glthread_rwlock_rdlock(NAME) 0
     651  # define glthread_rwlock_wrlock(NAME) 0
     652  # define glthread_rwlock_unlock(NAME) 0
     653  # define glthread_rwlock_destroy(NAME) 0
     654  
     655  /* --------------------- gl_recursive_lock_t datatype --------------------- */
     656  
     657  typedef int gl_recursive_lock_t;
     658  # define gl_recursive_lock_define(STORAGECLASS, NAME)
     659  # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
     660  # define glthread_recursive_lock_init(NAME) 0
     661  # define glthread_recursive_lock_lock(NAME) 0
     662  # define glthread_recursive_lock_unlock(NAME) 0
     663  # define glthread_recursive_lock_destroy(NAME) 0
     664  
     665  /* -------------------------- gl_once_t datatype -------------------------- */
     666  
     667  typedef int gl_once_t;
     668  # define gl_once_define(STORAGECLASS, NAME) \
     669      STORAGECLASS gl_once_t NAME = 0;
     670  # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
     671      (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
     672  
     673  #endif
     674  
     675  /* ========================================================================= */
     676  
     677  /* Macros with built-in error handling.  */
     678  
     679  /* -------------------------- gl_lock_t datatype -------------------------- */
     680  
     681  #define gl_lock_init(NAME) \
     682     do                                  \
     683       {                                 \
     684         if (glthread_lock_init (&NAME)) \
     685           abort ();                     \
     686       }                                 \
     687     while (0)
     688  #define gl_lock_lock(NAME) \
     689     do                                  \
     690       {                                 \
     691         if (glthread_lock_lock (&NAME)) \
     692           abort ();                     \
     693       }                                 \
     694     while (0)
     695  #define gl_lock_unlock(NAME) \
     696     do                                    \
     697       {                                   \
     698         if (glthread_lock_unlock (&NAME)) \
     699           abort ();                       \
     700       }                                   \
     701     while (0)
     702  #define gl_lock_destroy(NAME) \
     703     do                                     \
     704       {                                    \
     705         if (glthread_lock_destroy (&NAME)) \
     706           abort ();                        \
     707       }                                    \
     708     while (0)
     709  
     710  /* ------------------------- gl_rwlock_t datatype ------------------------- */
     711  
     712  #define gl_rwlock_init(NAME) \
     713     do                                    \
     714       {                                   \
     715         if (glthread_rwlock_init (&NAME)) \
     716           abort ();                       \
     717       }                                   \
     718     while (0)
     719  #define gl_rwlock_rdlock(NAME) \
     720     do                                      \
     721       {                                     \
     722         if (glthread_rwlock_rdlock (&NAME)) \
     723           abort ();                         \
     724       }                                     \
     725     while (0)
     726  #define gl_rwlock_wrlock(NAME) \
     727     do                                      \
     728       {                                     \
     729         if (glthread_rwlock_wrlock (&NAME)) \
     730           abort ();                         \
     731       }                                     \
     732     while (0)
     733  #define gl_rwlock_unlock(NAME) \
     734     do                                      \
     735       {                                     \
     736         if (glthread_rwlock_unlock (&NAME)) \
     737           abort ();                         \
     738       }                                     \
     739     while (0)
     740  #define gl_rwlock_destroy(NAME) \
     741     do                                       \
     742       {                                      \
     743         if (glthread_rwlock_destroy (&NAME)) \
     744           abort ();                          \
     745       }                                      \
     746     while (0)
     747  
     748  /* --------------------- gl_recursive_lock_t datatype --------------------- */
     749  
     750  #define gl_recursive_lock_init(NAME) \
     751     do                                            \
     752       {                                           \
     753         if (glthread_recursive_lock_init (&NAME)) \
     754           abort ();                               \
     755       }                                           \
     756     while (0)
     757  #define gl_recursive_lock_lock(NAME) \
     758     do                                            \
     759       {                                           \
     760         if (glthread_recursive_lock_lock (&NAME)) \
     761           abort ();                               \
     762       }                                           \
     763     while (0)
     764  #define gl_recursive_lock_unlock(NAME) \
     765     do                                              \
     766       {                                             \
     767         if (glthread_recursive_lock_unlock (&NAME)) \
     768           abort ();                                 \
     769       }                                             \
     770     while (0)
     771  #define gl_recursive_lock_destroy(NAME) \
     772     do                                               \
     773       {                                              \
     774         if (glthread_recursive_lock_destroy (&NAME)) \
     775           abort ();                                  \
     776       }                                              \
     777     while (0)
     778  
     779  /* -------------------------- gl_once_t datatype -------------------------- */
     780  
     781  #define gl_once(NAME, INITFUNCTION) \
     782     do                                           \
     783       {                                          \
     784         if (glthread_once (&NAME, INITFUNCTION)) \
     785           abort ();                              \
     786       }                                          \
     787     while (0)
     788  
     789  /* ========================================================================= */
     790  
     791  #endif /* _LOCK_H */