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