Back to index

courier  0.68.2
lock.h
Go to the documentation of this file.
00001 /* Locking in multithreaded situations.
00002    Copyright (C) 2005-2008 Free Software Foundation, Inc.
00003 
00004    This program is free software; you can redistribute it and/or modify it
00005    under the terms of the GNU Library General Public License as published
00006    by the Free Software Foundation; either version 2, or (at your option)
00007    any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public
00015    License along with this program; if not, write to the Free Software
00016    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00017    USA.  */
00018 
00019 /* Written by Bruno Haible <bruno@clisp.org>, 2005.
00020    Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
00021    gthr-win32.h.  */
00022 
00023 /* This file contains locking primitives for use with a given thread library.
00024    It does not contain primitives for creating threads or for other
00025    synchronization primitives.
00026 
00027    Normal (non-recursive) locks:
00028      Type:                gl_lock_t
00029      Declaration:         gl_lock_define(extern, name)
00030      Initializer:         gl_lock_define_initialized(, name)
00031      Initialization:      gl_lock_init (name);
00032      Taking the lock:     gl_lock_lock (name);
00033      Releasing the lock:  gl_lock_unlock (name);
00034      De-initialization:   gl_lock_destroy (name);
00035    Equivalent functions with control of error handling:
00036      Initialization:      err = glthread_lock_init (&name);
00037      Taking the lock:     err = glthread_lock_lock (&name);
00038      Releasing the lock:  err = glthread_lock_unlock (&name);
00039      De-initialization:   err = glthread_lock_destroy (&name);
00040 
00041    Read-Write (non-recursive) locks:
00042      Type:                gl_rwlock_t
00043      Declaration:         gl_rwlock_define(extern, name)
00044      Initializer:         gl_rwlock_define_initialized(, name)
00045      Initialization:      gl_rwlock_init (name);
00046      Taking the lock:     gl_rwlock_rdlock (name);
00047                           gl_rwlock_wrlock (name);
00048      Releasing the lock:  gl_rwlock_unlock (name);
00049      De-initialization:   gl_rwlock_destroy (name);
00050    Equivalent functions with control of error handling:
00051      Initialization:      err = glthread_rwlock_init (&name);
00052      Taking the lock:     err = glthread_rwlock_rdlock (&name);
00053                           err = glthread_rwlock_wrlock (&name);
00054      Releasing the lock:  err = glthread_rwlock_unlock (&name);
00055      De-initialization:   err = glthread_rwlock_destroy (&name);
00056 
00057    Recursive locks:
00058      Type:                gl_recursive_lock_t
00059      Declaration:         gl_recursive_lock_define(extern, name)
00060      Initializer:         gl_recursive_lock_define_initialized(, name)
00061      Initialization:      gl_recursive_lock_init (name);
00062      Taking the lock:     gl_recursive_lock_lock (name);
00063      Releasing the lock:  gl_recursive_lock_unlock (name);
00064      De-initialization:   gl_recursive_lock_destroy (name);
00065    Equivalent functions with control of error handling:
00066      Initialization:      err = glthread_recursive_lock_init (&name);
00067      Taking the lock:     err = glthread_recursive_lock_lock (&name);
00068      Releasing the lock:  err = glthread_recursive_lock_unlock (&name);
00069      De-initialization:   err = glthread_recursive_lock_destroy (&name);
00070 
00071   Once-only execution:
00072      Type:                gl_once_t
00073      Initializer:         gl_once_define(extern, name)
00074      Execution:           gl_once (name, initfunction);
00075    Equivalent functions with control of error handling:
00076      Execution:           err = glthread_once (&name, initfunction);
00077 */
00078 
00079 
00080 #ifndef _LOCK_H
00081 #define _LOCK_H
00082 
00083 #include <errno.h>
00084 #include <stdlib.h>
00085 
00086 /* ========================================================================= */
00087 
00088 #if USE_POSIX_THREADS
00089 
00090 /* Use the POSIX threads library.  */
00091 
00092 # include <pthread.h>
00093 
00094 # ifdef __cplusplus
00095 extern "C" {
00096 # endif
00097 
00098 # if PTHREAD_IN_USE_DETECTION_HARD
00099 
00100 /* The pthread_in_use() detection needs to be done at runtime.  */
00101 #  define pthread_in_use() \
00102      glthread_in_use ()
00103 extern int glthread_in_use (void);
00104 
00105 # endif
00106 
00107 # if USE_POSIX_THREADS_WEAK
00108 
00109 /* Use weak references to the POSIX threads library.  */
00110 
00111 /* Weak references avoid dragging in external libraries if the other parts
00112    of the program don't use them.  Here we use them, because we don't want
00113    every program that uses libintl to depend on libpthread.  This assumes
00114    that libpthread would not be loaded after libintl; i.e. if libintl is
00115    loaded first, by an executable that does not depend on libpthread, and
00116    then a module is dynamically loaded that depends on libpthread, libintl
00117    will not be multithread-safe.  */
00118 
00119 /* The way to test at runtime whether libpthread is present is to test
00120    whether a function pointer's value, such as &pthread_mutex_init, is
00121    non-NULL.  However, some versions of GCC have a bug through which, in
00122    PIC mode, &foo != NULL always evaluates to true if there is a direct
00123    call to foo(...) in the same function.  To avoid this, we test the
00124    address of a function in libpthread that we don't use.  */
00125 
00126 #  pragma weak pthread_mutex_init
00127 #  pragma weak pthread_mutex_lock
00128 #  pragma weak pthread_mutex_unlock
00129 #  pragma weak pthread_mutex_destroy
00130 #  pragma weak pthread_rwlock_init
00131 #  pragma weak pthread_rwlock_rdlock
00132 #  pragma weak pthread_rwlock_wrlock
00133 #  pragma weak pthread_rwlock_unlock
00134 #  pragma weak pthread_rwlock_destroy
00135 #  pragma weak pthread_once
00136 #  pragma weak pthread_cond_init
00137 #  pragma weak pthread_cond_wait
00138 #  pragma weak pthread_cond_signal
00139 #  pragma weak pthread_cond_broadcast
00140 #  pragma weak pthread_cond_destroy
00141 #  pragma weak pthread_mutexattr_init
00142 #  pragma weak pthread_mutexattr_settype
00143 #  pragma weak pthread_mutexattr_destroy
00144 #  ifndef pthread_self
00145 #   pragma weak pthread_self
00146 #  endif
00147 
00148 #  if !PTHREAD_IN_USE_DETECTION_HARD
00149 #   pragma weak pthread_cancel
00150 #   define pthread_in_use() (pthread_cancel != NULL)
00151 #  endif
00152 
00153 # else
00154 
00155 #  if !PTHREAD_IN_USE_DETECTION_HARD
00156 #   define pthread_in_use() 1
00157 #  endif
00158 
00159 # endif
00160 
00161 /* -------------------------- gl_lock_t datatype -------------------------- */
00162 
00163 typedef pthread_mutex_t gl_lock_t;
00164 # define gl_lock_define(STORAGECLASS, NAME) \
00165     STORAGECLASS pthread_mutex_t NAME;
00166 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
00167     STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
00168 # define gl_lock_initializer \
00169     PTHREAD_MUTEX_INITIALIZER
00170 # define glthread_lock_init(LOCK) \
00171     (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
00172 # define glthread_lock_lock(LOCK) \
00173     (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
00174 # define glthread_lock_unlock(LOCK) \
00175     (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
00176 # define glthread_lock_destroy(LOCK) \
00177     (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
00178 
00179 /* ------------------------- gl_rwlock_t datatype ------------------------- */
00180 
00181 # if HAVE_PTHREAD_RWLOCK
00182 
00183 #  ifdef PTHREAD_RWLOCK_INITIALIZER
00184 
00185 typedef pthread_rwlock_t gl_rwlock_t;
00186 #   define gl_rwlock_define(STORAGECLASS, NAME) \
00187       STORAGECLASS pthread_rwlock_t NAME;
00188 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
00189       STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
00190 #   define gl_rwlock_initializer \
00191       PTHREAD_RWLOCK_INITIALIZER
00192 #   define glthread_rwlock_init(LOCK) \
00193       (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
00194 #   define glthread_rwlock_rdlock(LOCK) \
00195       (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
00196 #   define glthread_rwlock_wrlock(LOCK) \
00197       (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
00198 #   define glthread_rwlock_unlock(LOCK) \
00199       (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
00200 #   define glthread_rwlock_destroy(LOCK) \
00201       (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
00202 
00203 #  else
00204 
00205 typedef struct
00206         {
00207           int initialized;
00208           pthread_mutex_t guard;   /* protects the initialization */
00209           pthread_rwlock_t rwlock; /* read-write lock */
00210         }
00211         gl_rwlock_t;
00212 #   define gl_rwlock_define(STORAGECLASS, NAME) \
00213       STORAGECLASS gl_rwlock_t NAME;
00214 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
00215       STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
00216 #   define gl_rwlock_initializer \
00217       { 0, PTHREAD_MUTEX_INITIALIZER }
00218 #   define glthread_rwlock_init(LOCK) \
00219       (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
00220 #   define glthread_rwlock_rdlock(LOCK) \
00221       (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
00222 #   define glthread_rwlock_wrlock(LOCK) \
00223       (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
00224 #   define glthread_rwlock_unlock(LOCK) \
00225       (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
00226 #   define glthread_rwlock_destroy(LOCK) \
00227       (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
00228 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
00229 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
00230 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
00231 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
00232 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
00233 
00234 #  endif
00235 
00236 # else
00237 
00238 typedef struct
00239         {
00240           pthread_mutex_t lock; /* protects the remaining fields */
00241           pthread_cond_t waiting_readers; /* waiting readers */
00242           pthread_cond_t waiting_writers; /* waiting writers */
00243           unsigned int waiting_writers_count; /* number of waiting writers */
00244           int runcount; /* number of readers running, or -1 when a writer runs */
00245         }
00246         gl_rwlock_t;
00247 # define gl_rwlock_define(STORAGECLASS, NAME) \
00248     STORAGECLASS gl_rwlock_t NAME;
00249 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
00250     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
00251 # define gl_rwlock_initializer \
00252     { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
00253 # define glthread_rwlock_init(LOCK) \
00254     (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
00255 # define glthread_rwlock_rdlock(LOCK) \
00256     (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
00257 # define glthread_rwlock_wrlock(LOCK) \
00258     (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
00259 # define glthread_rwlock_unlock(LOCK) \
00260     (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
00261 # define glthread_rwlock_destroy(LOCK) \
00262     (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
00263 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
00264 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
00265 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
00266 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
00267 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
00268 
00269 # endif
00270 
00271 /* --------------------- gl_recursive_lock_t datatype --------------------- */
00272 
00273 # if HAVE_PTHREAD_MUTEX_RECURSIVE
00274 
00275 #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00276 
00277 typedef pthread_mutex_t gl_recursive_lock_t;
00278 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
00279       STORAGECLASS pthread_mutex_t NAME;
00280 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
00281       STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
00282 #   ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
00283 #    define gl_recursive_lock_initializer \
00284        PTHREAD_RECURSIVE_MUTEX_INITIALIZER
00285 #   else
00286 #    define gl_recursive_lock_initializer \
00287        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
00288 #   endif
00289 #   define glthread_recursive_lock_init(LOCK) \
00290       (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
00291 #   define glthread_recursive_lock_lock(LOCK) \
00292       (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
00293 #   define glthread_recursive_lock_unlock(LOCK) \
00294       (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
00295 #   define glthread_recursive_lock_destroy(LOCK) \
00296       (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
00297 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
00298 
00299 #  else
00300 
00301 typedef struct
00302         {
00303           pthread_mutex_t recmutex; /* recursive mutex */
00304           pthread_mutex_t guard;    /* protects the initialization */
00305           int initialized;
00306         }
00307         gl_recursive_lock_t;
00308 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
00309       STORAGECLASS gl_recursive_lock_t NAME;
00310 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
00311       STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
00312 #   define gl_recursive_lock_initializer \
00313       { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
00314 #   define glthread_recursive_lock_init(LOCK) \
00315       (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
00316 #   define glthread_recursive_lock_lock(LOCK) \
00317       (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
00318 #   define glthread_recursive_lock_unlock(LOCK) \
00319       (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
00320 #   define glthread_recursive_lock_destroy(LOCK) \
00321       (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
00322 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
00323 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
00324 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
00325 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
00326 
00327 #  endif
00328 
00329 # else
00330 
00331 /* Old versions of POSIX threads on Solaris did not have recursive locks.
00332    We have to implement them ourselves.  */
00333 
00334 typedef struct
00335         {
00336           pthread_mutex_t mutex;
00337           pthread_t owner;
00338           unsigned long depth;
00339         }
00340         gl_recursive_lock_t;
00341 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
00342      STORAGECLASS gl_recursive_lock_t NAME;
00343 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
00344      STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
00345 #  define gl_recursive_lock_initializer \
00346      { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
00347 #  define glthread_recursive_lock_init(LOCK) \
00348      (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
00349 #  define glthread_recursive_lock_lock(LOCK) \
00350      (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
00351 #  define glthread_recursive_lock_unlock(LOCK) \
00352      (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
00353 #  define glthread_recursive_lock_destroy(LOCK) \
00354      (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
00355 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
00356 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
00357 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
00358 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
00359 
00360 # endif
00361 
00362 /* -------------------------- gl_once_t datatype -------------------------- */
00363 
00364 typedef pthread_once_t gl_once_t;
00365 # define gl_once_define(STORAGECLASS, NAME) \
00366     STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
00367 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
00368     (pthread_in_use ()                                                         \
00369      ? pthread_once (ONCE_CONTROL, INITFUNCTION)                               \
00370      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
00371 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
00372 
00373 # ifdef __cplusplus
00374 }
00375 # endif
00376 
00377 #endif
00378 
00379 /* ========================================================================= */
00380 
00381 #if USE_PTH_THREADS
00382 
00383 /* Use the GNU Pth threads library.  */
00384 
00385 # include <pth.h>
00386 
00387 # ifdef __cplusplus
00388 extern "C" {
00389 # endif
00390 
00391 # if USE_PTH_THREADS_WEAK
00392 
00393 /* Use weak references to the GNU Pth threads library.  */
00394 
00395 #  pragma weak pth_mutex_init
00396 #  pragma weak pth_mutex_acquire
00397 #  pragma weak pth_mutex_release
00398 #  pragma weak pth_rwlock_init
00399 #  pragma weak pth_rwlock_acquire
00400 #  pragma weak pth_rwlock_release
00401 #  pragma weak pth_once
00402 
00403 #  pragma weak pth_cancel
00404 #  define pth_in_use() (pth_cancel != NULL)
00405 
00406 # else
00407 
00408 #  define pth_in_use() 1
00409 
00410 # endif
00411 
00412 /* -------------------------- gl_lock_t datatype -------------------------- */
00413 
00414 typedef pth_mutex_t gl_lock_t;
00415 # define gl_lock_define(STORAGECLASS, NAME) \
00416     STORAGECLASS pth_mutex_t NAME;
00417 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
00418     STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
00419 # define gl_lock_initializer \
00420     PTH_MUTEX_INIT
00421 # define glthread_lock_init(LOCK) \
00422     (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
00423 # define glthread_lock_lock(LOCK) \
00424     (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
00425 # define glthread_lock_unlock(LOCK) \
00426     (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
00427 # define glthread_lock_destroy(LOCK) \
00428     ((void)(LOCK), 0)
00429 
00430 /* ------------------------- gl_rwlock_t datatype ------------------------- */
00431 
00432 typedef pth_rwlock_t gl_rwlock_t;
00433 #  define gl_rwlock_define(STORAGECLASS, NAME) \
00434      STORAGECLASS pth_rwlock_t NAME;
00435 #  define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
00436      STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
00437 #  define gl_rwlock_initializer \
00438      PTH_RWLOCK_INIT
00439 #  define glthread_rwlock_init(LOCK) \
00440      (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0)
00441 #  define glthread_rwlock_rdlock(LOCK) \
00442      (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0)
00443 #  define glthread_rwlock_wrlock(LOCK) \
00444      (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0)
00445 #  define glthread_rwlock_unlock(LOCK) \
00446      (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0)
00447 #  define glthread_rwlock_destroy(LOCK) \
00448      ((void)(LOCK), 0)
00449 
00450 /* --------------------- gl_recursive_lock_t datatype --------------------- */
00451 
00452 /* In Pth, mutexes are recursive by default.  */
00453 typedef pth_mutex_t gl_recursive_lock_t;
00454 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
00455      STORAGECLASS pth_mutex_t NAME;
00456 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
00457      STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
00458 #  define gl_recursive_lock_initializer \
00459      PTH_MUTEX_INIT
00460 #  define glthread_recursive_lock_init(LOCK) \
00461      (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
00462 #  define glthread_recursive_lock_lock(LOCK) \
00463      (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
00464 #  define glthread_recursive_lock_unlock(LOCK) \
00465      (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
00466 #  define glthread_recursive_lock_destroy(LOCK) \
00467      ((void)(LOCK), 0)
00468 
00469 /* -------------------------- gl_once_t datatype -------------------------- */
00470 
00471 typedef pth_once_t gl_once_t;
00472 # define gl_once_define(STORAGECLASS, NAME) \
00473     STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
00474 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
00475     (pth_in_use ()                                                             \
00476      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
00477      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
00478 extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void));
00479 extern int glthread_once_singlethreaded (pth_once_t *once_control);
00480 
00481 # ifdef __cplusplus
00482 }
00483 # endif
00484 
00485 #endif
00486 
00487 /* ========================================================================= */
00488 
00489 #if USE_SOLARIS_THREADS
00490 
00491 /* Use the old Solaris threads library.  */
00492 
00493 # include <thread.h>
00494 # include <synch.h>
00495 
00496 # ifdef __cplusplus
00497 extern "C" {
00498 # endif
00499 
00500 # if USE_SOLARIS_THREADS_WEAK
00501 
00502 /* Use weak references to the old Solaris threads library.  */
00503 
00504 #  pragma weak mutex_init
00505 #  pragma weak mutex_lock
00506 #  pragma weak mutex_unlock
00507 #  pragma weak mutex_destroy
00508 #  pragma weak rwlock_init
00509 #  pragma weak rw_rdlock
00510 #  pragma weak rw_wrlock
00511 #  pragma weak rw_unlock
00512 #  pragma weak rwlock_destroy
00513 #  pragma weak thr_self
00514 
00515 #  pragma weak thr_suspend
00516 #  define thread_in_use() (thr_suspend != NULL)
00517 
00518 # else
00519 
00520 #  define thread_in_use() 1
00521 
00522 # endif
00523 
00524 /* -------------------------- gl_lock_t datatype -------------------------- */
00525 
00526 typedef mutex_t gl_lock_t;
00527 # define gl_lock_define(STORAGECLASS, NAME) \
00528     STORAGECLASS mutex_t NAME;
00529 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
00530     STORAGECLASS mutex_t NAME = gl_lock_initializer;
00531 # define gl_lock_initializer \
00532     DEFAULTMUTEX
00533 # define glthread_lock_init(LOCK) \
00534     (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
00535 # define glthread_lock_lock(LOCK) \
00536     (thread_in_use () ? mutex_lock (LOCK) : 0)
00537 # define glthread_lock_unlock(LOCK) \
00538     (thread_in_use () ? mutex_unlock (LOCK) : 0)
00539 # define glthread_lock_destroy(LOCK) \
00540     (thread_in_use () ? mutex_destroy (LOCK) : 0)
00541 
00542 /* ------------------------- gl_rwlock_t datatype ------------------------- */
00543 
00544 typedef rwlock_t gl_rwlock_t;
00545 # define gl_rwlock_define(STORAGECLASS, NAME) \
00546     STORAGECLASS rwlock_t NAME;
00547 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
00548     STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
00549 # define gl_rwlock_initializer \
00550     DEFAULTRWLOCK
00551 # define glthread_rwlock_init(LOCK) \
00552     (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
00553 # define glthread_rwlock_rdlock(LOCK) \
00554     (thread_in_use () ? rw_rdlock (LOCK) : 0)
00555 # define glthread_rwlock_wrlock(LOCK) \
00556     (thread_in_use () ? rw_wrlock (LOCK) : 0)
00557 # define glthread_rwlock_unlock(LOCK) \
00558     (thread_in_use () ? rw_unlock (LOCK) : 0)
00559 # define glthread_rwlock_destroy(LOCK) \
00560     (thread_in_use () ? rwlock_destroy (LOCK) : 0)
00561 
00562 /* --------------------- gl_recursive_lock_t datatype --------------------- */
00563 
00564 /* Old Solaris threads did not have recursive locks.
00565    We have to implement them ourselves.  */
00566 
00567 typedef struct
00568         {
00569           mutex_t mutex;
00570           thread_t owner;
00571           unsigned long depth;
00572         }
00573         gl_recursive_lock_t;
00574 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
00575     STORAGECLASS gl_recursive_lock_t NAME;
00576 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
00577     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
00578 # define gl_recursive_lock_initializer \
00579     { DEFAULTMUTEX, (thread_t) 0, 0 }
00580 # define glthread_recursive_lock_init(LOCK) \
00581     (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
00582 # define glthread_recursive_lock_lock(LOCK) \
00583     (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
00584 # define glthread_recursive_lock_unlock(LOCK) \
00585     (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
00586 # define glthread_recursive_lock_destroy(LOCK) \
00587     (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
00588 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
00589 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
00590 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
00591 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
00592 
00593 /* -------------------------- gl_once_t datatype -------------------------- */
00594 
00595 typedef struct
00596         {
00597           volatile int inited;
00598           mutex_t mutex;
00599         }
00600         gl_once_t;
00601 # define gl_once_define(STORAGECLASS, NAME) \
00602     STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
00603 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
00604     (thread_in_use ()                                                          \
00605      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
00606      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
00607 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
00608 extern int glthread_once_singlethreaded (gl_once_t *once_control);
00609 
00610 # ifdef __cplusplus
00611 }
00612 # endif
00613 
00614 #endif
00615 
00616 /* ========================================================================= */
00617 
00618 #if USE_WIN32_THREADS
00619 
00620 # include <windows.h>
00621 
00622 # ifdef __cplusplus
00623 extern "C" {
00624 # endif
00625 
00626 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
00627    Semaphore types, because
00628      - we need only to synchronize inside a single process (address space),
00629        not inter-process locking,
00630      - we don't need to support trylock operations.  (TryEnterCriticalSection
00631        does not work on Windows 95/98/ME.  Packages that need trylock usually
00632        define their own mutex type.)  */
00633 
00634 /* There is no way to statically initialize a CRITICAL_SECTION.  It needs
00635    to be done lazily, once only.  For this we need spinlocks.  */
00636 
00637 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
00638 
00639 /* -------------------------- gl_lock_t datatype -------------------------- */
00640 
00641 typedef struct
00642         {
00643           gl_spinlock_t guard; /* protects the initialization */
00644           CRITICAL_SECTION lock;
00645         }
00646         gl_lock_t;
00647 # define gl_lock_define(STORAGECLASS, NAME) \
00648     STORAGECLASS gl_lock_t NAME;
00649 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
00650     STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
00651 # define gl_lock_initializer \
00652     { { 0, -1 } }
00653 # define glthread_lock_init(LOCK) \
00654     (glthread_lock_init_func (LOCK), 0)
00655 # define glthread_lock_lock(LOCK) \
00656     glthread_lock_lock_func (LOCK)
00657 # define glthread_lock_unlock(LOCK) \
00658     glthread_lock_unlock_func (LOCK)
00659 # define glthread_lock_destroy(LOCK) \
00660     glthread_lock_destroy_func (LOCK)
00661 extern void glthread_lock_init_func (gl_lock_t *lock);
00662 extern int glthread_lock_lock_func (gl_lock_t *lock);
00663 extern int glthread_lock_unlock_func (gl_lock_t *lock);
00664 extern int glthread_lock_destroy_func (gl_lock_t *lock);
00665 
00666 /* ------------------------- gl_rwlock_t datatype ------------------------- */
00667 
00668 /* It is impossible to implement read-write locks using plain locks, without
00669    introducing an extra thread dedicated to managing read-write locks.
00670    Therefore here we need to use the low-level Event type.  */
00671 
00672 typedef struct
00673         {
00674           HANDLE *array; /* array of waiting threads, each represented by an event */
00675           unsigned int count; /* number of waiting threads */
00676           unsigned int alloc; /* length of allocated array */
00677           unsigned int offset; /* index of first waiting thread in array */
00678         }
00679         gl_carray_waitqueue_t;
00680 typedef struct
00681         {
00682           gl_spinlock_t guard; /* protects the initialization */
00683           CRITICAL_SECTION lock; /* protects the remaining fields */
00684           gl_carray_waitqueue_t waiting_readers; /* waiting readers */
00685           gl_carray_waitqueue_t waiting_writers; /* waiting writers */
00686           int runcount; /* number of readers running, or -1 when a writer runs */
00687         }
00688         gl_rwlock_t;
00689 # define gl_rwlock_define(STORAGECLASS, NAME) \
00690     STORAGECLASS gl_rwlock_t NAME;
00691 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
00692     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
00693 # define gl_rwlock_initializer \
00694     { { 0, -1 } }
00695 # define glthread_rwlock_init(LOCK) \
00696     (glthread_rwlock_init_func (LOCK), 0)
00697 # define glthread_rwlock_rdlock(LOCK) \
00698     glthread_rwlock_rdlock_func (LOCK)
00699 # define glthread_rwlock_wrlock(LOCK) \
00700     glthread_rwlock_wrlock_func (LOCK)
00701 # define glthread_rwlock_unlock(LOCK) \
00702     glthread_rwlock_unlock_func (LOCK)
00703 # define glthread_rwlock_destroy(LOCK) \
00704     glthread_rwlock_destroy_func (LOCK)
00705 extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
00706 extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock);
00707 extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock);
00708 extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock);
00709 extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock);
00710 
00711 /* --------------------- gl_recursive_lock_t datatype --------------------- */
00712 
00713 /* The Win32 documentation says that CRITICAL_SECTION already implements a
00714    recursive lock.  But we need not rely on it: It's easy to implement a
00715    recursive lock without this assumption.  */
00716 
00717 typedef struct
00718         {
00719           gl_spinlock_t guard; /* protects the initialization */
00720           DWORD owner;
00721           unsigned long depth;
00722           CRITICAL_SECTION lock;
00723         }
00724         gl_recursive_lock_t;
00725 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
00726     STORAGECLASS gl_recursive_lock_t NAME;
00727 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
00728     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
00729 # define gl_recursive_lock_initializer \
00730     { { 0, -1 }, 0, 0 }
00731 # define glthread_recursive_lock_init(LOCK) \
00732     (glthread_recursive_lock_init_func (LOCK), 0)
00733 # define glthread_recursive_lock_lock(LOCK) \
00734     glthread_recursive_lock_lock_func (LOCK)
00735 # define glthread_recursive_lock_unlock(LOCK) \
00736     glthread_recursive_lock_unlock_func (LOCK)
00737 # define glthread_recursive_lock_destroy(LOCK) \
00738     glthread_recursive_lock_destroy_func (LOCK)
00739 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
00740 extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock);
00741 extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock);
00742 extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock);
00743 
00744 /* -------------------------- gl_once_t datatype -------------------------- */
00745 
00746 typedef struct
00747         {
00748           volatile int inited;
00749           volatile long started;
00750           CRITICAL_SECTION lock;
00751         }
00752         gl_once_t;
00753 # define gl_once_define(STORAGECLASS, NAME) \
00754     STORAGECLASS gl_once_t NAME = { -1, -1 };
00755 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
00756     (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
00757 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
00758 
00759 # ifdef __cplusplus
00760 }
00761 # endif
00762 
00763 #endif
00764 
00765 /* ========================================================================= */
00766 
00767 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
00768 
00769 /* Provide dummy implementation if threads are not supported.  */
00770 
00771 /* -------------------------- gl_lock_t datatype -------------------------- */
00772 
00773 typedef int gl_lock_t;
00774 # define gl_lock_define(STORAGECLASS, NAME)
00775 # define gl_lock_define_initialized(STORAGECLASS, NAME)
00776 # define glthread_lock_init(NAME) 0
00777 # define glthread_lock_lock(NAME) 0
00778 # define glthread_lock_unlock(NAME) 0
00779 # define glthread_lock_destroy(NAME) 0
00780 
00781 /* ------------------------- gl_rwlock_t datatype ------------------------- */
00782 
00783 typedef int gl_rwlock_t;
00784 # define gl_rwlock_define(STORAGECLASS, NAME)
00785 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
00786 # define glthread_rwlock_init(NAME) 0
00787 # define glthread_rwlock_rdlock(NAME) 0
00788 # define glthread_rwlock_wrlock(NAME) 0
00789 # define glthread_rwlock_unlock(NAME) 0
00790 # define glthread_rwlock_destroy(NAME) 0
00791 
00792 /* --------------------- gl_recursive_lock_t datatype --------------------- */
00793 
00794 typedef int gl_recursive_lock_t;
00795 # define gl_recursive_lock_define(STORAGECLASS, NAME)
00796 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
00797 # define glthread_recursive_lock_init(NAME) 0
00798 # define glthread_recursive_lock_lock(NAME) 0
00799 # define glthread_recursive_lock_unlock(NAME) 0
00800 # define glthread_recursive_lock_destroy(NAME) 0
00801 
00802 /* -------------------------- gl_once_t datatype -------------------------- */
00803 
00804 typedef int gl_once_t;
00805 # define gl_once_define(STORAGECLASS, NAME) \
00806     STORAGECLASS gl_once_t NAME = 0;
00807 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
00808     (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
00809 
00810 #endif
00811 
00812 /* ========================================================================= */
00813 
00814 /* Macros with built-in error handling.  */
00815 
00816 /* -------------------------- gl_lock_t datatype -------------------------- */
00817 
00818 #define gl_lock_init(NAME) \
00819    do                                  \
00820      {                                 \
00821        if (glthread_lock_init (&NAME)) \
00822          abort ();                     \
00823      }                                 \
00824    while (0)
00825 #define gl_lock_lock(NAME) \
00826    do                                  \
00827      {                                 \
00828        if (glthread_lock_lock (&NAME)) \
00829          abort ();                     \
00830      }                                 \
00831    while (0)
00832 #define gl_lock_unlock(NAME) \
00833    do                                    \
00834      {                                   \
00835        if (glthread_lock_unlock (&NAME)) \
00836          abort ();                       \
00837      }                                   \
00838    while (0)
00839 #define gl_lock_destroy(NAME) \
00840    do                                     \
00841      {                                    \
00842        if (glthread_lock_destroy (&NAME)) \
00843          abort ();                        \
00844      }                                    \
00845    while (0)
00846 
00847 /* ------------------------- gl_rwlock_t datatype ------------------------- */
00848 
00849 #define gl_rwlock_init(NAME) \
00850    do                                    \
00851      {                                   \
00852        if (glthread_rwlock_init (&NAME)) \
00853          abort ();                       \
00854      }                                   \
00855    while (0)
00856 #define gl_rwlock_rdlock(NAME) \
00857    do                                      \
00858      {                                     \
00859        if (glthread_rwlock_rdlock (&NAME)) \
00860          abort ();                         \
00861      }                                     \
00862    while (0)
00863 #define gl_rwlock_wrlock(NAME) \
00864    do                                      \
00865      {                                     \
00866        if (glthread_rwlock_wrlock (&NAME)) \
00867          abort ();                         \
00868      }                                     \
00869    while (0)
00870 #define gl_rwlock_unlock(NAME) \
00871    do                                      \
00872      {                                     \
00873        if (glthread_rwlock_unlock (&NAME)) \
00874          abort ();                         \
00875      }                                     \
00876    while (0)
00877 #define gl_rwlock_destroy(NAME) \
00878    do                                       \
00879      {                                      \
00880        if (glthread_rwlock_destroy (&NAME)) \
00881          abort ();                          \
00882      }                                      \
00883    while (0)
00884 
00885 /* --------------------- gl_recursive_lock_t datatype --------------------- */
00886 
00887 #define gl_recursive_lock_init(NAME) \
00888    do                                            \
00889      {                                           \
00890        if (glthread_recursive_lock_init (&NAME)) \
00891          abort ();                               \
00892      }                                           \
00893    while (0)
00894 #define gl_recursive_lock_lock(NAME) \
00895    do                                            \
00896      {                                           \
00897        if (glthread_recursive_lock_lock (&NAME)) \
00898          abort ();                               \
00899      }                                           \
00900    while (0)
00901 #define gl_recursive_lock_unlock(NAME) \
00902    do                                              \
00903      {                                             \
00904        if (glthread_recursive_lock_unlock (&NAME)) \
00905          abort ();                                 \
00906      }                                             \
00907    while (0)
00908 #define gl_recursive_lock_destroy(NAME) \
00909    do                                               \
00910      {                                              \
00911        if (glthread_recursive_lock_destroy (&NAME)) \
00912          abort ();                                  \
00913      }                                              \
00914    while (0)
00915 
00916 /* -------------------------- gl_once_t datatype -------------------------- */
00917 
00918 #define gl_once(NAME, INITFUNCTION) \
00919    do                                           \
00920      {                                          \
00921        if (glthread_once (&NAME, INITFUNCTION)) \
00922          abort ();                              \
00923      }                                          \
00924    while (0)
00925 
00926 /* ========================================================================= */
00927 
00928 #endif /* _LOCK_H */