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