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 it
5    under the terms of the GNU Library General Public License as published
6    by the Free Software Foundation; either version 2, 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 GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public
15    License along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17    USA.  */
18 
19 /* Written by Bruno Haible <bruno@clisp.org>, 2005.
20    Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
21    gthr-win32.h.  */
22 
23 /* This file contains locking primitives for use with a given thread library.
24    It does not contain primitives for creating threads or for other
25    synchronization primitives.
26 
27    Normal (non-recursive) locks:
28      Type:                gl_lock_t
29      Declaration:         gl_lock_define(extern, name)
30      Initializer:         gl_lock_define_initialized(, name)
31      Initialization:      gl_lock_init (name);
32      Taking the lock:     gl_lock_lock (name);
33      Releasing the lock:  gl_lock_unlock (name);
34      De-initialization:   gl_lock_destroy (name);
35 
36    Read-Write (non-recursive) locks:
37      Type:                gl_rwlock_t
38      Declaration:         gl_rwlock_define(extern, name)
39      Initializer:         gl_rwlock_define_initialized(, name)
40      Initialization:      gl_rwlock_init (name);
41      Taking the lock:     gl_rwlock_rdlock (name);
42                           gl_rwlock_wrlock (name);
43      Releasing the lock:  gl_rwlock_unlock (name);
44      De-initialization:   gl_rwlock_destroy (name);
45 
46    Recursive locks:
47      Type:                gl_recursive_lock_t
48      Declaration:         gl_recursive_lock_define(extern, name)
49      Initializer:         gl_recursive_lock_define_initialized(, name)
50      Initialization:      gl_recursive_lock_init (name);
51      Taking the lock:     gl_recursive_lock_lock (name);
52      Releasing the lock:  gl_recursive_lock_unlock (name);
53      De-initialization:   gl_recursive_lock_destroy (name);
54 
55   Once-only execution:
56      Type:                gl_once_t
57      Initializer:         gl_once_define(extern, name)
58      Execution:           gl_once (name, initfunction);
59 */
60 
61 
62 #ifndef _LOCK_H
63 #define _LOCK_H
64 
65 /* ========================================================================= */
66 
67 #if USE_POSIX_THREADS
68 
69 /* Use the POSIX threads library.  */
70 
71 # include <pthread.h>
72 # include <stdlib.h>
73 
74 # ifdef __cplusplus
75 extern "C" {
76 # endif
77 
78 # if PTHREAD_IN_USE_DETECTION_HARD
79 
80 /* The pthread_in_use() detection needs to be done at runtime.  */
81 #  define pthread_in_use() \
82      glthread_in_use ()
83 extern int glthread_in_use (void);
84 
85 # endif
86 
87 # if USE_POSIX_THREADS_WEAK
88 
89 /* Use weak references to the POSIX threads library.  */
90 
91 /* Weak references avoid dragging in external libraries if the other parts
92    of the program don't use them.  Here we use them, because we don't want
93    every program that uses libintl to depend on libpthread.  This assumes
94    that libpthread would not be loaded after libintl; i.e. if libintl is
95    loaded first, by an executable that does not depend on libpthread, and
96    then a module is dynamically loaded that depends on libpthread, libintl
97    will not be multithread-safe.  */
98 
99 /* The way to test at runtime whether libpthread is present is to test
100    whether a function pointer's value, such as &pthread_mutex_init, is
101    non-NULL.  However, some versions of GCC have a bug through which, in
102    PIC mode, &foo != NULL always evaluates to true if there is a direct
103    call to foo(...) in the same function.  To avoid this, we test the
104    address of a function in libpthread that we don't use.  */
105 
106 #  pragma weak pthread_mutex_init
107 #  pragma weak pthread_mutex_lock
108 #  pragma weak pthread_mutex_unlock
109 #  pragma weak pthread_mutex_destroy
110 #  pragma weak pthread_rwlock_init
111 #  pragma weak pthread_rwlock_rdlock
112 #  pragma weak pthread_rwlock_wrlock
113 #  pragma weak pthread_rwlock_unlock
114 #  pragma weak pthread_rwlock_destroy
115 #  pragma weak pthread_once
116 #  pragma weak pthread_cond_init
117 #  pragma weak pthread_cond_wait
118 #  pragma weak pthread_cond_signal
119 #  pragma weak pthread_cond_broadcast
120 #  pragma weak pthread_cond_destroy
121 #  pragma weak pthread_mutexattr_init
122 #  pragma weak pthread_mutexattr_settype
123 #  pragma weak pthread_mutexattr_destroy
124 #  ifndef pthread_self
125 #   pragma weak pthread_self
126 #  endif
127 
128 #  if !PTHREAD_IN_USE_DETECTION_HARD
129 #   pragma weak pthread_cancel
130 #   define pthread_in_use() (pthread_cancel != NULL)
131 #  endif
132 
133 # else
134 
135 #  if !PTHREAD_IN_USE_DETECTION_HARD
136 #   define pthread_in_use() 1
137 #  endif
138 
139 # endif
140 
141 /* -------------------------- gl_lock_t datatype -------------------------- */
142 
143 typedef pthread_mutex_t gl_lock_t;
144 # define gl_lock_define(STORAGECLASS, NAME) \
145     STORAGECLASS pthread_mutex_t NAME;
146 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
147     STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
148 # define gl_lock_initializer \
149     PTHREAD_MUTEX_INITIALIZER
150 # define gl_lock_init(NAME) \
151     do                                                                  \
152       {                                                                 \
153         if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) \
154           abort ();                                                     \
155       }                                                                 \
156     while (0)
157 # define gl_lock_lock(NAME) \
158     do                                                            \
159       {                                                           \
160         if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) \
161           abort ();                                               \
162       }                                                           \
163     while (0)
164 # define gl_lock_unlock(NAME) \
165     do                                                              \
166       {                                                             \
167         if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) \
168           abort ();                                                 \
169       }                                                             \
170     while (0)
171 # define gl_lock_destroy(NAME) \
172     do                                                               \
173       {                                                              \
174         if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) \
175           abort ();                                                  \
176       }                                                              \
177     while (0)
178 
179 /* ------------------------- gl_rwlock_t datatype ------------------------- */
180 
181 # if HAVE_PTHREAD_RWLOCK
182 
183 #  ifdef PTHREAD_RWLOCK_INITIALIZER
184 
185 typedef pthread_rwlock_t gl_rwlock_t;
186 #   define gl_rwlock_define(STORAGECLASS, NAME) \
187       STORAGECLASS pthread_rwlock_t NAME;
188 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
189       STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
190 #   define gl_rwlock_initializer \
191       PTHREAD_RWLOCK_INITIALIZER
192 #   define gl_rwlock_init(NAME) \
193       do                                                                   \
194         {                                                                  \
195           if (pthread_in_use () && pthread_rwlock_init (&NAME, NULL) != 0) \
196             abort ();                                                      \
197         }                                                                  \
198       while (0)
199 #   define gl_rwlock_rdlock(NAME) \
200       do                                                               \
201         {                                                              \
202           if (pthread_in_use () && pthread_rwlock_rdlock (&NAME) != 0) \
203             abort ();                                                  \
204         }                                                              \
205       while (0)
206 #   define gl_rwlock_wrlock(NAME) \
207       do                                                               \
208         {                                                              \
209           if (pthread_in_use () && pthread_rwlock_wrlock (&NAME) != 0) \
210             abort ();                                                  \
211         }                                                              \
212       while (0)
213 #   define gl_rwlock_unlock(NAME) \
214       do                                                               \
215         {                                                              \
216           if (pthread_in_use () && pthread_rwlock_unlock (&NAME) != 0) \
217             abort ();                                                  \
218         }                                                              \
219       while (0)
220 #   define gl_rwlock_destroy(NAME) \
221       do                                                                \
222         {                                                               \
223           if (pthread_in_use () && pthread_rwlock_destroy (&NAME) != 0) \
224             abort ();                                                   \
225         }                                                               \
226       while (0)
227 
228 #  else
229 
230 typedef struct
231         {
232           int initialized;
233           pthread_mutex_t guard;   /* protects the initialization */
234           pthread_rwlock_t rwlock; /* read-write lock */
235         }
236         gl_rwlock_t;
237 #   define gl_rwlock_define(STORAGECLASS, NAME) \
238       STORAGECLASS gl_rwlock_t NAME;
239 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
240       STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
241 #   define gl_rwlock_initializer \
242       { 0, PTHREAD_MUTEX_INITIALIZER }
243 #   define gl_rwlock_init(NAME) \
244       do                                  \
245         {                                 \
246           if (pthread_in_use ())          \
247             glthread_rwlock_init (&NAME); \
248         }                                 \
249       while (0)
250 #   define gl_rwlock_rdlock(NAME) \
251       do                                    \
252         {                                   \
253           if (pthread_in_use ())            \
254             glthread_rwlock_rdlock (&NAME); \
255         }                                   \
256       while (0)
257 #   define gl_rwlock_wrlock(NAME) \
258       do                                    \
259         {                                   \
260           if (pthread_in_use ())            \
261             glthread_rwlock_wrlock (&NAME); \
262         }                                   \
263       while (0)
264 #   define gl_rwlock_unlock(NAME) \
265       do                                    \
266         {                                   \
267           if (pthread_in_use ())            \
268             glthread_rwlock_unlock (&NAME); \
269         }                                   \
270       while (0)
271 #   define gl_rwlock_destroy(NAME) \
272       do                                     \
273         {                                    \
274           if (pthread_in_use ())             \
275             glthread_rwlock_destroy (&NAME); \
276         }                                    \
277       while (0)
278 extern void glthread_rwlock_init (gl_rwlock_t *lock);
279 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
280 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
281 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
282 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
283 
284 #  endif
285 
286 # else
287 
288 typedef struct
289         {
290           pthread_mutex_t lock; /* protects the remaining fields */
291           pthread_cond_t waiting_readers; /* waiting readers */
292           pthread_cond_t waiting_writers; /* waiting writers */
293           unsigned int waiting_writers_count; /* number of waiting writers */
294           int runcount; /* number of readers running, or -1 when a writer runs */
295         }
296         gl_rwlock_t;
297 # define gl_rwlock_define(STORAGECLASS, NAME) \
298     STORAGECLASS gl_rwlock_t NAME;
299 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
300     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
301 # define gl_rwlock_initializer \
302     { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
303 # define gl_rwlock_init(NAME) \
304     do                                  \
305       {                                 \
306         if (pthread_in_use ())          \
307           glthread_rwlock_init (&NAME); \
308       }                                 \
309     while (0)
310 # define gl_rwlock_rdlock(NAME) \
311     do                                    \
312       {                                   \
313         if (pthread_in_use ())            \
314           glthread_rwlock_rdlock (&NAME); \
315       }                                   \
316     while (0)
317 # define gl_rwlock_wrlock(NAME) \
318     do                                    \
319       {                                   \
320         if (pthread_in_use ())            \
321           glthread_rwlock_wrlock (&NAME); \
322       }                                   \
323     while (0)
324 # define gl_rwlock_unlock(NAME) \
325     do                                    \
326       {                                   \
327         if (pthread_in_use ())            \
328           glthread_rwlock_unlock (&NAME); \
329       }                                   \
330     while (0)
331 # define gl_rwlock_destroy(NAME) \
332     do                                     \
333       {                                    \
334         if (pthread_in_use ())             \
335           glthread_rwlock_destroy (&NAME); \
336       }                                    \
337     while (0)
338 extern void glthread_rwlock_init (gl_rwlock_t *lock);
339 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
340 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
341 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
342 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
343 
344 # endif
345 
346 /* --------------------- gl_recursive_lock_t datatype --------------------- */
347 
348 # if HAVE_PTHREAD_MUTEX_RECURSIVE
349 
350 #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
351 
352 typedef pthread_mutex_t gl_recursive_lock_t;
353 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
354       STORAGECLASS pthread_mutex_t NAME;
355 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
356       STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
357 #   ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
358 #    define gl_recursive_lock_initializer \
359        PTHREAD_RECURSIVE_MUTEX_INITIALIZER
360 #   else
361 #    define gl_recursive_lock_initializer \
362        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
363 #   endif
364 #   define gl_recursive_lock_init(NAME) \
365       do                                                                  \
366         {                                                                 \
367           if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) \
368             abort ();                                                     \
369         }                                                                 \
370       while (0)
371 #   define gl_recursive_lock_lock(NAME) \
372       do                                                            \
373         {                                                           \
374           if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) \
375             abort ();                                               \
376         }                                                           \
377       while (0)
378 #   define gl_recursive_lock_unlock(NAME) \
379       do                                                              \
380         {                                                             \
381           if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) \
382             abort ();                                                 \
383         }                                                             \
384       while (0)
385 #   define gl_recursive_lock_destroy(NAME) \
386       do                                                               \
387         {                                                              \
388           if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) \
389             abort ();                                                  \
390         }                                                              \
391       while (0)
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 */
1106