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