New upstream version 1.10
[debian/gzip] / lib / glthread / lock.h
1 /* Locking in multithreaded situations.
2    Copyright (C) 2005-2018 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-solaris.h,
19    gthr-win32.h.  */
20
21 /* This file contains locking primitives for use with a given thread library.
22    It does not contain primitives for creating threads or for other
23    synchronization primitives.
24
25    Normal (non-recursive) locks:
26      Type:                gl_lock_t
27      Declaration:         gl_lock_define(extern, name)
28      Initializer:         gl_lock_define_initialized(, name)
29      Initialization:      gl_lock_init (name);
30      Taking the lock:     gl_lock_lock (name);
31      Releasing the lock:  gl_lock_unlock (name);
32      De-initialization:   gl_lock_destroy (name);
33    Equivalent functions with control of error handling:
34      Initialization:      err = glthread_lock_init (&name);
35      Taking the lock:     err = glthread_lock_lock (&name);
36      Releasing the lock:  err = glthread_lock_unlock (&name);
37      De-initialization:   err = glthread_lock_destroy (&name);
38
39    Read-Write (non-recursive) locks:
40      Type:                gl_rwlock_t
41      Declaration:         gl_rwlock_define(extern, name)
42      Initializer:         gl_rwlock_define_initialized(, name)
43      Initialization:      gl_rwlock_init (name);
44      Taking the lock:     gl_rwlock_rdlock (name);
45                           gl_rwlock_wrlock (name);
46      Releasing the lock:  gl_rwlock_unlock (name);
47      De-initialization:   gl_rwlock_destroy (name);
48    Equivalent functions with control of error handling:
49      Initialization:      err = glthread_rwlock_init (&name);
50      Taking the lock:     err = glthread_rwlock_rdlock (&name);
51                           err = glthread_rwlock_wrlock (&name);
52      Releasing the lock:  err = glthread_rwlock_unlock (&name);
53      De-initialization:   err = glthread_rwlock_destroy (&name);
54
55    Recursive locks:
56      Type:                gl_recursive_lock_t
57      Declaration:         gl_recursive_lock_define(extern, name)
58      Initializer:         gl_recursive_lock_define_initialized(, name)
59      Initialization:      gl_recursive_lock_init (name);
60      Taking the lock:     gl_recursive_lock_lock (name);
61      Releasing the lock:  gl_recursive_lock_unlock (name);
62      De-initialization:   gl_recursive_lock_destroy (name);
63    Equivalent functions with control of error handling:
64      Initialization:      err = glthread_recursive_lock_init (&name);
65      Taking the lock:     err = glthread_recursive_lock_lock (&name);
66      Releasing the lock:  err = glthread_recursive_lock_unlock (&name);
67      De-initialization:   err = glthread_recursive_lock_destroy (&name);
68
69   Once-only execution:
70      Type:                gl_once_t
71      Initializer:         gl_once_define(extern, name)
72      Execution:           gl_once (name, initfunction);
73    Equivalent functions with control of error handling:
74      Execution:           err = glthread_once (&name, initfunction);
75 */
76
77
78 #ifndef _LOCK_H
79 #define _LOCK_H
80
81 #include <errno.h>
82 #include <stdlib.h>
83
84 /* ========================================================================= */
85
86 #if USE_POSIX_THREADS
87
88 /* Use the POSIX threads library.  */
89
90 # include <pthread.h>
91
92 # ifdef __cplusplus
93 extern "C" {
94 # endif
95
96 # if PTHREAD_IN_USE_DETECTION_HARD
97
98 /* The pthread_in_use() detection needs to be done at runtime.  */
99 #  define pthread_in_use() \
100      glthread_in_use ()
101 extern int glthread_in_use (void);
102
103 # endif
104
105 # if USE_POSIX_THREADS_WEAK
106
107 /* Use weak references to the POSIX threads library.  */
108
109 /* Weak references avoid dragging in external libraries if the other parts
110    of the program don't use them.  Here we use them, because we don't want
111    every program that uses libintl to depend on libpthread.  This assumes
112    that libpthread would not be loaded after libintl; i.e. if libintl is
113    loaded first, by an executable that does not depend on libpthread, and
114    then a module is dynamically loaded that depends on libpthread, libintl
115    will not be multithread-safe.  */
116
117 /* The way to test at runtime whether libpthread is present is to test
118    whether a function pointer's value, such as &pthread_mutex_init, is
119    non-NULL.  However, some versions of GCC have a bug through which, in
120    PIC mode, &foo != NULL always evaluates to true if there is a direct
121    call to foo(...) in the same function.  To avoid this, we test the
122    address of a function in libpthread that we don't use.  */
123
124 #  pragma weak pthread_mutex_init
125 #  pragma weak pthread_mutex_lock
126 #  pragma weak pthread_mutex_unlock
127 #  pragma weak pthread_mutex_destroy
128 #  pragma weak pthread_rwlock_init
129 #  pragma weak pthread_rwlock_rdlock
130 #  pragma weak pthread_rwlock_wrlock
131 #  pragma weak pthread_rwlock_unlock
132 #  pragma weak pthread_rwlock_destroy
133 #  pragma weak pthread_once
134 #  pragma weak pthread_cond_init
135 #  pragma weak pthread_cond_wait
136 #  pragma weak pthread_cond_signal
137 #  pragma weak pthread_cond_broadcast
138 #  pragma weak pthread_cond_destroy
139 #  pragma weak pthread_mutexattr_init
140 #  pragma weak pthread_mutexattr_settype
141 #  pragma weak pthread_mutexattr_destroy
142 #  pragma weak pthread_rwlockattr_init
143 #  if __GNU_LIBRARY__ > 1
144 #   pragma weak pthread_rwlockattr_setkind_np
145 #  endif
146 #  pragma weak pthread_rwlockattr_destroy
147 #  ifndef pthread_self
148 #   pragma weak pthread_self
149 #  endif
150
151 #  if !PTHREAD_IN_USE_DETECTION_HARD
152     /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols
153        can be used to determine whether libpthread is in use.  These are:
154          pthread_mutexattr_gettype
155          pthread_rwlockattr_destroy
156          pthread_rwlockattr_init
157      */
158 #   pragma weak pthread_mutexattr_gettype
159 #   define pthread_in_use() (pthread_mutexattr_gettype != NULL)
160 #  endif
161
162 # else
163
164 #  if !PTHREAD_IN_USE_DETECTION_HARD
165 #   define pthread_in_use() 1
166 #  endif
167
168 # endif
169
170 /* -------------------------- gl_lock_t datatype -------------------------- */
171
172 typedef pthread_mutex_t gl_lock_t;
173 # define gl_lock_define(STORAGECLASS, NAME) \
174     STORAGECLASS pthread_mutex_t NAME;
175 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
176     STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
177 # define gl_lock_initializer \
178     PTHREAD_MUTEX_INITIALIZER
179 # define glthread_lock_init(LOCK) \
180     (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
181 # define glthread_lock_lock(LOCK) \
182     (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
183 # define glthread_lock_unlock(LOCK) \
184     (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
185 # define glthread_lock_destroy(LOCK) \
186     (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
187
188 /* ------------------------- gl_rwlock_t datatype ------------------------- */
189
190 # if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
191
192 #  ifdef PTHREAD_RWLOCK_INITIALIZER
193
194 typedef pthread_rwlock_t gl_rwlock_t;
195 #   define gl_rwlock_define(STORAGECLASS, NAME) \
196       STORAGECLASS pthread_rwlock_t NAME;
197 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
198       STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
199 #   if HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
200 #    define gl_rwlock_initializer \
201        PTHREAD_RWLOCK_INITIALIZER
202 #    define glthread_rwlock_init(LOCK) \
203        (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
204 #   else /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
205 #    define gl_rwlock_initializer \
206        PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
207 #    define glthread_rwlock_init(LOCK) \
208        (pthread_in_use () ? glthread_rwlock_init_for_glibc (LOCK) : 0)
209 extern int glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock);
210 #   endif
211 #   define glthread_rwlock_rdlock(LOCK) \
212       (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
213 #   define glthread_rwlock_wrlock(LOCK) \
214       (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
215 #   define glthread_rwlock_unlock(LOCK) \
216       (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
217 #   define glthread_rwlock_destroy(LOCK) \
218       (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
219
220 #  else
221
222 typedef struct
223         {
224           int initialized;
225           pthread_mutex_t guard;   /* protects the initialization */
226           pthread_rwlock_t rwlock; /* read-write lock */
227         }
228         gl_rwlock_t;
229 #   define gl_rwlock_define(STORAGECLASS, NAME) \
230       STORAGECLASS gl_rwlock_t NAME;
231 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
232       STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
233 #   define gl_rwlock_initializer \
234       { 0, PTHREAD_MUTEX_INITIALIZER }
235 #   define glthread_rwlock_init(LOCK) \
236       (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
237 #   define glthread_rwlock_rdlock(LOCK) \
238       (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
239 #   define glthread_rwlock_wrlock(LOCK) \
240       (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
241 #   define glthread_rwlock_unlock(LOCK) \
242       (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
243 #   define glthread_rwlock_destroy(LOCK) \
244       (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
245 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
246 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
247 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
248 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
249 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
250
251 #  endif
252
253 # else
254
255 typedef struct
256         {
257           pthread_mutex_t lock; /* protects the remaining fields */
258           pthread_cond_t waiting_readers; /* waiting readers */
259           pthread_cond_t waiting_writers; /* waiting writers */
260           unsigned int waiting_writers_count; /* number of waiting writers */
261           int runcount; /* number of readers running, or -1 when a writer runs */
262         }
263         gl_rwlock_t;
264 # define gl_rwlock_define(STORAGECLASS, NAME) \
265     STORAGECLASS gl_rwlock_t NAME;
266 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
267     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
268 # define gl_rwlock_initializer \
269     { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
270 # define glthread_rwlock_init(LOCK) \
271     (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
272 # define glthread_rwlock_rdlock(LOCK) \
273     (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
274 # define glthread_rwlock_wrlock(LOCK) \
275     (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
276 # define glthread_rwlock_unlock(LOCK) \
277     (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
278 # define glthread_rwlock_destroy(LOCK) \
279     (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
280 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
281 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
282 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
283 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
284 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
285
286 # endif
287
288 /* --------------------- gl_recursive_lock_t datatype --------------------- */
289
290 # if HAVE_PTHREAD_MUTEX_RECURSIVE
291
292 #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
293
294 typedef pthread_mutex_t gl_recursive_lock_t;
295 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
296       STORAGECLASS pthread_mutex_t NAME;
297 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
298       STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
299 #   ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
300 #    define gl_recursive_lock_initializer \
301        PTHREAD_RECURSIVE_MUTEX_INITIALIZER
302 #   else
303 #    define gl_recursive_lock_initializer \
304        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
305 #   endif
306 #   define glthread_recursive_lock_init(LOCK) \
307       (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
308 #   define glthread_recursive_lock_lock(LOCK) \
309       (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
310 #   define glthread_recursive_lock_unlock(LOCK) \
311       (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
312 #   define glthread_recursive_lock_destroy(LOCK) \
313       (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
314 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
315
316 #  else
317
318 typedef struct
319         {
320           pthread_mutex_t recmutex; /* recursive mutex */
321           pthread_mutex_t guard;    /* protects the initialization */
322           int initialized;
323         }
324         gl_recursive_lock_t;
325 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
326       STORAGECLASS gl_recursive_lock_t NAME;
327 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
328       STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
329 #   define gl_recursive_lock_initializer \
330       { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
331 #   define glthread_recursive_lock_init(LOCK) \
332       (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
333 #   define glthread_recursive_lock_lock(LOCK) \
334       (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
335 #   define glthread_recursive_lock_unlock(LOCK) \
336       (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
337 #   define glthread_recursive_lock_destroy(LOCK) \
338       (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
339 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
340 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
341 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
342 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
343
344 #  endif
345
346 # else
347
348 /* Old versions of POSIX threads on Solaris did not have recursive locks.
349    We have to implement them ourselves.  */
350
351 typedef struct
352         {
353           pthread_mutex_t mutex;
354           pthread_t owner;
355           unsigned long depth;
356         }
357         gl_recursive_lock_t;
358 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
359      STORAGECLASS gl_recursive_lock_t NAME;
360 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
361      STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
362 #  define gl_recursive_lock_initializer \
363      { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
364 #  define glthread_recursive_lock_init(LOCK) \
365      (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
366 #  define glthread_recursive_lock_lock(LOCK) \
367      (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
368 #  define glthread_recursive_lock_unlock(LOCK) \
369      (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
370 #  define glthread_recursive_lock_destroy(LOCK) \
371      (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
372 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
373 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
374 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
375 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
376
377 # endif
378
379 /* -------------------------- gl_once_t datatype -------------------------- */
380
381 typedef pthread_once_t gl_once_t;
382 # define gl_once_define(STORAGECLASS, NAME) \
383     STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
384 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
385     (pthread_in_use ()                                                         \
386      ? pthread_once (ONCE_CONTROL, INITFUNCTION)                               \
387      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
388 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
389
390 # ifdef __cplusplus
391 }
392 # endif
393
394 #endif
395
396 /* ========================================================================= */
397
398 #if USE_PTH_THREADS
399
400 /* Use the GNU Pth threads library.  */
401
402 # include <pth.h>
403
404 # ifdef __cplusplus
405 extern "C" {
406 # endif
407
408 # if USE_PTH_THREADS_WEAK
409
410 /* Use weak references to the GNU Pth threads library.  */
411
412 #  pragma weak pth_mutex_init
413 #  pragma weak pth_mutex_acquire
414 #  pragma weak pth_mutex_release
415 #  pragma weak pth_rwlock_init
416 #  pragma weak pth_rwlock_acquire
417 #  pragma weak pth_rwlock_release
418 #  pragma weak pth_once
419
420 #  pragma weak pth_cancel
421 #  define pth_in_use() (pth_cancel != NULL)
422
423 # else
424
425 #  define pth_in_use() 1
426
427 # endif
428
429 /* -------------------------- gl_lock_t datatype -------------------------- */
430
431 typedef pth_mutex_t gl_lock_t;
432 # define gl_lock_define(STORAGECLASS, NAME) \
433     STORAGECLASS pth_mutex_t NAME;
434 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
435     STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
436 # define gl_lock_initializer \
437     PTH_MUTEX_INIT
438 # define glthread_lock_init(LOCK) \
439     (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
440 # define glthread_lock_lock(LOCK) \
441     (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
442 # define glthread_lock_unlock(LOCK) \
443     (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
444 # define glthread_lock_destroy(LOCK) \
445     ((void)(LOCK), 0)
446
447 /* ------------------------- gl_rwlock_t datatype ------------------------- */
448
449 /* Pth pth_rwlock_acquire always prefers readers.  No autoconf test so far.  */
450 # if HAVE_PTH_RWLOCK_ACQUIRE_PREFER_WRITER
451
452 typedef pth_rwlock_t gl_rwlock_t;
453 #  define gl_rwlock_define(STORAGECLASS, NAME) \
454      STORAGECLASS pth_rwlock_t NAME;
455 #  define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
456      STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
457 #  define gl_rwlock_initializer \
458      PTH_RWLOCK_INIT
459 #  define glthread_rwlock_init(LOCK) \
460      (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0)
461 #  define glthread_rwlock_rdlock(LOCK) \
462      (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0)
463 #  define glthread_rwlock_wrlock(LOCK) \
464      (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0)
465 #  define glthread_rwlock_unlock(LOCK) \
466      (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0)
467 #  define glthread_rwlock_destroy(LOCK) \
468      ((void)(LOCK), 0)
469
470 # else
471
472 typedef struct
473         {
474           int initialized;
475           pth_mutex_t lock; /* protects the remaining fields */
476           pth_cond_t waiting_readers; /* waiting readers */
477           pth_cond_t waiting_writers; /* waiting writers */
478           unsigned int waiting_writers_count; /* number of waiting writers */
479           int runcount; /* number of readers running, or -1 when a writer runs */
480         }
481         gl_rwlock_t;
482 #  define gl_rwlock_define(STORAGECLASS, NAME) \
483      STORAGECLASS gl_rwlock_t NAME;
484 #  define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
485      STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
486 #  define gl_rwlock_initializer \
487      { 0 }
488 #  define glthread_rwlock_init(LOCK) \
489      (pth_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
490 #  define glthread_rwlock_rdlock(LOCK) \
491      (pth_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
492 #  define glthread_rwlock_wrlock(LOCK) \
493      (pth_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
494 #  define glthread_rwlock_unlock(LOCK) \
495      (pth_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
496 #  define glthread_rwlock_destroy(LOCK) \
497      (pth_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
498 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
499 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
500 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
501 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
502 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
503
504 # endif
505
506 /* --------------------- gl_recursive_lock_t datatype --------------------- */
507
508 /* In Pth, mutexes are recursive by default.  */
509 typedef pth_mutex_t gl_recursive_lock_t;
510 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
511      STORAGECLASS pth_mutex_t NAME;
512 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
513      STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
514 #  define gl_recursive_lock_initializer \
515      PTH_MUTEX_INIT
516 #  define glthread_recursive_lock_init(LOCK) \
517      (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
518 #  define glthread_recursive_lock_lock(LOCK) \
519      (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
520 #  define glthread_recursive_lock_unlock(LOCK) \
521      (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
522 #  define glthread_recursive_lock_destroy(LOCK) \
523      ((void)(LOCK), 0)
524
525 /* -------------------------- gl_once_t datatype -------------------------- */
526
527 typedef pth_once_t gl_once_t;
528 # define gl_once_define(STORAGECLASS, NAME) \
529     STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
530 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
531     (pth_in_use ()                                                             \
532      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
533      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
534 extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void));
535 extern int glthread_once_singlethreaded (pth_once_t *once_control);
536
537 # ifdef __cplusplus
538 }
539 # endif
540
541 #endif
542
543 /* ========================================================================= */
544
545 #if USE_SOLARIS_THREADS
546
547 /* Use the old Solaris threads library.  */
548
549 # include <thread.h>
550 # include <synch.h>
551
552 # ifdef __cplusplus
553 extern "C" {
554 # endif
555
556 # if USE_SOLARIS_THREADS_WEAK
557
558 /* Use weak references to the old Solaris threads library.  */
559
560 #  pragma weak mutex_init
561 #  pragma weak mutex_lock
562 #  pragma weak mutex_unlock
563 #  pragma weak mutex_destroy
564 #  pragma weak rwlock_init
565 #  pragma weak rw_rdlock
566 #  pragma weak rw_wrlock
567 #  pragma weak rw_unlock
568 #  pragma weak rwlock_destroy
569 #  pragma weak thr_self
570
571 #  pragma weak thr_suspend
572 #  define thread_in_use() (thr_suspend != NULL)
573
574 # else
575
576 #  define thread_in_use() 1
577
578 # endif
579
580 /* -------------------------- gl_lock_t datatype -------------------------- */
581
582 typedef mutex_t gl_lock_t;
583 # define gl_lock_define(STORAGECLASS, NAME) \
584     STORAGECLASS mutex_t NAME;
585 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
586     STORAGECLASS mutex_t NAME = gl_lock_initializer;
587 # define gl_lock_initializer \
588     DEFAULTMUTEX
589 # define glthread_lock_init(LOCK) \
590     (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
591 # define glthread_lock_lock(LOCK) \
592     (thread_in_use () ? mutex_lock (LOCK) : 0)
593 # define glthread_lock_unlock(LOCK) \
594     (thread_in_use () ? mutex_unlock (LOCK) : 0)
595 # define glthread_lock_destroy(LOCK) \
596     (thread_in_use () ? mutex_destroy (LOCK) : 0)
597
598 /* ------------------------- gl_rwlock_t datatype ------------------------- */
599
600 typedef rwlock_t gl_rwlock_t;
601 # define gl_rwlock_define(STORAGECLASS, NAME) \
602     STORAGECLASS rwlock_t NAME;
603 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
604     STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
605 # define gl_rwlock_initializer \
606     DEFAULTRWLOCK
607 # define glthread_rwlock_init(LOCK) \
608     (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
609 # define glthread_rwlock_rdlock(LOCK) \
610     (thread_in_use () ? rw_rdlock (LOCK) : 0)
611 # define glthread_rwlock_wrlock(LOCK) \
612     (thread_in_use () ? rw_wrlock (LOCK) : 0)
613 # define glthread_rwlock_unlock(LOCK) \
614     (thread_in_use () ? rw_unlock (LOCK) : 0)
615 # define glthread_rwlock_destroy(LOCK) \
616     (thread_in_use () ? rwlock_destroy (LOCK) : 0)
617
618 /* --------------------- gl_recursive_lock_t datatype --------------------- */
619
620 /* Old Solaris threads did not have recursive locks.
621    We have to implement them ourselves.  */
622
623 typedef struct
624         {
625           mutex_t mutex;
626           thread_t owner;
627           unsigned long depth;
628         }
629         gl_recursive_lock_t;
630 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
631     STORAGECLASS gl_recursive_lock_t NAME;
632 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
633     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
634 # define gl_recursive_lock_initializer \
635     { DEFAULTMUTEX, (thread_t) 0, 0 }
636 # define glthread_recursive_lock_init(LOCK) \
637     (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
638 # define glthread_recursive_lock_lock(LOCK) \
639     (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
640 # define glthread_recursive_lock_unlock(LOCK) \
641     (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
642 # define glthread_recursive_lock_destroy(LOCK) \
643     (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
644 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
645 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
646 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
647 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
648
649 /* -------------------------- gl_once_t datatype -------------------------- */
650
651 typedef struct
652         {
653           volatile int inited;
654           mutex_t mutex;
655         }
656         gl_once_t;
657 # define gl_once_define(STORAGECLASS, NAME) \
658     STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
659 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
660     (thread_in_use ()                                                          \
661      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
662      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
663 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
664 extern int glthread_once_singlethreaded (gl_once_t *once_control);
665
666 # ifdef __cplusplus
667 }
668 # endif
669
670 #endif
671
672 /* ========================================================================= */
673
674 #if USE_WINDOWS_THREADS
675
676 # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
677 # include <windows.h>
678
679 # ifdef __cplusplus
680 extern "C" {
681 # endif
682
683 /* We can use CRITICAL_SECTION directly, rather than the native Windows Event,
684    Mutex, Semaphore types, because
685      - we need only to synchronize inside a single process (address space),
686        not inter-process locking,
687      - we don't need to support trylock operations.  (TryEnterCriticalSection
688        does not work on Windows 95/98/ME.  Packages that need trylock usually
689        define their own mutex type.)  */
690
691 /* There is no way to statically initialize a CRITICAL_SECTION.  It needs
692    to be done lazily, once only.  For this we need spinlocks.  */
693
694 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
695
696 /* -------------------------- gl_lock_t datatype -------------------------- */
697
698 typedef struct
699         {
700           gl_spinlock_t guard; /* protects the initialization */
701           CRITICAL_SECTION lock;
702         }
703         gl_lock_t;
704 # define gl_lock_define(STORAGECLASS, NAME) \
705     STORAGECLASS gl_lock_t NAME;
706 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
707     STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
708 # define gl_lock_initializer \
709     { { 0, -1 } }
710 # define glthread_lock_init(LOCK) \
711     (glthread_lock_init_func (LOCK), 0)
712 # define glthread_lock_lock(LOCK) \
713     glthread_lock_lock_func (LOCK)
714 # define glthread_lock_unlock(LOCK) \
715     glthread_lock_unlock_func (LOCK)
716 # define glthread_lock_destroy(LOCK) \
717     glthread_lock_destroy_func (LOCK)
718 extern void glthread_lock_init_func (gl_lock_t *lock);
719 extern int glthread_lock_lock_func (gl_lock_t *lock);
720 extern int glthread_lock_unlock_func (gl_lock_t *lock);
721 extern int glthread_lock_destroy_func (gl_lock_t *lock);
722
723 /* ------------------------- gl_rwlock_t datatype ------------------------- */
724
725 /* It is impossible to implement read-write locks using plain locks, without
726    introducing an extra thread dedicated to managing read-write locks.
727    Therefore here we need to use the low-level Event type.  */
728
729 typedef struct
730         {
731           HANDLE *array; /* array of waiting threads, each represented by an event */
732           unsigned int count; /* number of waiting threads */
733           unsigned int alloc; /* length of allocated array */
734           unsigned int offset; /* index of first waiting thread in array */
735         }
736         gl_carray_waitqueue_t;
737 typedef struct
738         {
739           gl_spinlock_t guard; /* protects the initialization */
740           CRITICAL_SECTION lock; /* protects the remaining fields */
741           gl_carray_waitqueue_t waiting_readers; /* waiting readers */
742           gl_carray_waitqueue_t waiting_writers; /* waiting writers */
743           int runcount; /* number of readers running, or -1 when a writer runs */
744         }
745         gl_rwlock_t;
746 # define gl_rwlock_define(STORAGECLASS, NAME) \
747     STORAGECLASS gl_rwlock_t NAME;
748 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
749     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
750 # define gl_rwlock_initializer \
751     { { 0, -1 } }
752 # define glthread_rwlock_init(LOCK) \
753     (glthread_rwlock_init_func (LOCK), 0)
754 # define glthread_rwlock_rdlock(LOCK) \
755     glthread_rwlock_rdlock_func (LOCK)
756 # define glthread_rwlock_wrlock(LOCK) \
757     glthread_rwlock_wrlock_func (LOCK)
758 # define glthread_rwlock_unlock(LOCK) \
759     glthread_rwlock_unlock_func (LOCK)
760 # define glthread_rwlock_destroy(LOCK) \
761     glthread_rwlock_destroy_func (LOCK)
762 extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
763 extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock);
764 extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock);
765 extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock);
766 extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock);
767
768 /* --------------------- gl_recursive_lock_t datatype --------------------- */
769
770 /* The native Windows documentation says that CRITICAL_SECTION already
771    implements a recursive lock.  But we need not rely on it: It's easy to
772    implement a recursive lock without this assumption.  */
773
774 typedef struct
775         {
776           gl_spinlock_t guard; /* protects the initialization */
777           DWORD owner;
778           unsigned long depth;
779           CRITICAL_SECTION lock;
780         }
781         gl_recursive_lock_t;
782 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
783     STORAGECLASS gl_recursive_lock_t NAME;
784 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
785     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
786 # define gl_recursive_lock_initializer \
787     { { 0, -1 }, 0, 0 }
788 # define glthread_recursive_lock_init(LOCK) \
789     (glthread_recursive_lock_init_func (LOCK), 0)
790 # define glthread_recursive_lock_lock(LOCK) \
791     glthread_recursive_lock_lock_func (LOCK)
792 # define glthread_recursive_lock_unlock(LOCK) \
793     glthread_recursive_lock_unlock_func (LOCK)
794 # define glthread_recursive_lock_destroy(LOCK) \
795     glthread_recursive_lock_destroy_func (LOCK)
796 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
797 extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock);
798 extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock);
799 extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock);
800
801 /* -------------------------- gl_once_t datatype -------------------------- */
802
803 typedef struct
804         {
805           volatile int inited;
806           volatile long started;
807           CRITICAL_SECTION lock;
808         }
809         gl_once_t;
810 # define gl_once_define(STORAGECLASS, NAME) \
811     STORAGECLASS gl_once_t NAME = { -1, -1 };
812 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
813     (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
814 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
815
816 # ifdef __cplusplus
817 }
818 # endif
819
820 #endif
821
822 /* ========================================================================= */
823
824 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
825
826 /* Provide dummy implementation if threads are not supported.  */
827
828 /* -------------------------- gl_lock_t datatype -------------------------- */
829
830 typedef int gl_lock_t;
831 # define gl_lock_define(STORAGECLASS, NAME)
832 # define gl_lock_define_initialized(STORAGECLASS, NAME)
833 # define glthread_lock_init(NAME) 0
834 # define glthread_lock_lock(NAME) 0
835 # define glthread_lock_unlock(NAME) 0
836 # define glthread_lock_destroy(NAME) 0
837
838 /* ------------------------- gl_rwlock_t datatype ------------------------- */
839
840 typedef int gl_rwlock_t;
841 # define gl_rwlock_define(STORAGECLASS, NAME)
842 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
843 # define glthread_rwlock_init(NAME) 0
844 # define glthread_rwlock_rdlock(NAME) 0
845 # define glthread_rwlock_wrlock(NAME) 0
846 # define glthread_rwlock_unlock(NAME) 0
847 # define glthread_rwlock_destroy(NAME) 0
848
849 /* --------------------- gl_recursive_lock_t datatype --------------------- */
850
851 typedef int gl_recursive_lock_t;
852 # define gl_recursive_lock_define(STORAGECLASS, NAME)
853 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
854 # define glthread_recursive_lock_init(NAME) 0
855 # define glthread_recursive_lock_lock(NAME) 0
856 # define glthread_recursive_lock_unlock(NAME) 0
857 # define glthread_recursive_lock_destroy(NAME) 0
858
859 /* -------------------------- gl_once_t datatype -------------------------- */
860
861 typedef int gl_once_t;
862 # define gl_once_define(STORAGECLASS, NAME) \
863     STORAGECLASS gl_once_t NAME = 0;
864 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
865     (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
866
867 #endif
868
869 /* ========================================================================= */
870
871 /* Macros with built-in error handling.  */
872
873 /* -------------------------- gl_lock_t datatype -------------------------- */
874
875 #define gl_lock_init(NAME) \
876    do                                  \
877      {                                 \
878        if (glthread_lock_init (&NAME)) \
879          abort ();                     \
880      }                                 \
881    while (0)
882 #define gl_lock_lock(NAME) \
883    do                                  \
884      {                                 \
885        if (glthread_lock_lock (&NAME)) \
886          abort ();                     \
887      }                                 \
888    while (0)
889 #define gl_lock_unlock(NAME) \
890    do                                    \
891      {                                   \
892        if (glthread_lock_unlock (&NAME)) \
893          abort ();                       \
894      }                                   \
895    while (0)
896 #define gl_lock_destroy(NAME) \
897    do                                     \
898      {                                    \
899        if (glthread_lock_destroy (&NAME)) \
900          abort ();                        \
901      }                                    \
902    while (0)
903
904 /* ------------------------- gl_rwlock_t datatype ------------------------- */
905
906 #define gl_rwlock_init(NAME) \
907    do                                    \
908      {                                   \
909        if (glthread_rwlock_init (&NAME)) \
910          abort ();                       \
911      }                                   \
912    while (0)
913 #define gl_rwlock_rdlock(NAME) \
914    do                                      \
915      {                                     \
916        if (glthread_rwlock_rdlock (&NAME)) \
917          abort ();                         \
918      }                                     \
919    while (0)
920 #define gl_rwlock_wrlock(NAME) \
921    do                                      \
922      {                                     \
923        if (glthread_rwlock_wrlock (&NAME)) \
924          abort ();                         \
925      }                                     \
926    while (0)
927 #define gl_rwlock_unlock(NAME) \
928    do                                      \
929      {                                     \
930        if (glthread_rwlock_unlock (&NAME)) \
931          abort ();                         \
932      }                                     \
933    while (0)
934 #define gl_rwlock_destroy(NAME) \
935    do                                       \
936      {                                      \
937        if (glthread_rwlock_destroy (&NAME)) \
938          abort ();                          \
939      }                                      \
940    while (0)
941
942 /* --------------------- gl_recursive_lock_t datatype --------------------- */
943
944 #define gl_recursive_lock_init(NAME) \
945    do                                            \
946      {                                           \
947        if (glthread_recursive_lock_init (&NAME)) \
948          abort ();                               \
949      }                                           \
950    while (0)
951 #define gl_recursive_lock_lock(NAME) \
952    do                                            \
953      {                                           \
954        if (glthread_recursive_lock_lock (&NAME)) \
955          abort ();                               \
956      }                                           \
957    while (0)
958 #define gl_recursive_lock_unlock(NAME) \
959    do                                              \
960      {                                             \
961        if (glthread_recursive_lock_unlock (&NAME)) \
962          abort ();                                 \
963      }                                             \
964    while (0)
965 #define gl_recursive_lock_destroy(NAME) \
966    do                                               \
967      {                                              \
968        if (glthread_recursive_lock_destroy (&NAME)) \
969          abort ();                                  \
970      }                                              \
971    while (0)
972
973 /* -------------------------- gl_once_t datatype -------------------------- */
974
975 #define gl_once(NAME, INITFUNCTION) \
976    do                                           \
977      {                                          \
978        if (glthread_once (&NAME, INITFUNCTION)) \
979          abort ();                              \
980      }                                          \
981    while (0)
982
983 /* ========================================================================= */
984
985 #endif /* _LOCK_H */