Unicode character classification functions.
[gnulib.git] / lib / 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 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
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 () && pthread_mutex_init (&NAME, NULL) != 0) \
367             abort ();                                                     \
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
392 #  else
393
394 typedef struct
395         {
396           pthread_mutex_t recmutex; /* recursive mutex */
397           pthread_mutex_t guard;    /* protects the initialization */
398           int initialized;
399         }
400         gl_recursive_lock_t;
401 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
402       STORAGECLASS gl_recursive_lock_t NAME;
403 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
404       STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
405 #   define gl_recursive_lock_initializer \
406       { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
407 #   define gl_recursive_lock_init(NAME) \
408       do                                          \
409         {                                         \
410           if (pthread_in_use ())                  \
411             glthread_recursive_lock_init (&NAME); \
412         }                                         \
413       while (0)
414 #   define gl_recursive_lock_lock(NAME) \
415       do                                          \
416         {                                         \
417           if (pthread_in_use ())                  \
418             glthread_recursive_lock_lock (&NAME); \
419         }                                         \
420       while (0)
421 #   define gl_recursive_lock_unlock(NAME) \
422       do                                            \
423         {                                           \
424           if (pthread_in_use ())                    \
425             glthread_recursive_lock_unlock (&NAME); \
426         }                                           \
427       while (0)
428 #   define gl_recursive_lock_destroy(NAME) \
429       do                                             \
430         {                                            \
431           if (pthread_in_use ())                     \
432             glthread_recursive_lock_destroy (&NAME); \
433         }                                            \
434       while (0)
435 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
436 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
437 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
438 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
439
440 #  endif
441
442 # else
443
444 /* Old versions of POSIX threads on Solaris did not have recursive locks.
445    We have to implement them ourselves.  */
446
447 typedef struct
448         {
449           pthread_mutex_t mutex;
450           pthread_t owner;
451           unsigned long depth;
452         }
453         gl_recursive_lock_t;
454 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
455      STORAGECLASS gl_recursive_lock_t NAME;
456 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
457      STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
458 #  define gl_recursive_lock_initializer \
459      { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
460 #  define gl_recursive_lock_init(NAME) \
461      do                                          \
462        {                                         \
463          if (pthread_in_use ())                  \
464            glthread_recursive_lock_init (&NAME); \
465        }                                         \
466      while (0)
467 #  define gl_recursive_lock_lock(NAME) \
468      do                                          \
469        {                                         \
470          if (pthread_in_use ())                  \
471            glthread_recursive_lock_lock (&NAME); \
472        }                                         \
473      while (0)
474 #  define gl_recursive_lock_unlock(NAME) \
475      do                                            \
476        {                                           \
477          if (pthread_in_use ())                    \
478            glthread_recursive_lock_unlock (&NAME); \
479        }                                           \
480      while (0)
481 #  define gl_recursive_lock_destroy(NAME) \
482      do                                             \
483        {                                            \
484          if (pthread_in_use ())                     \
485            glthread_recursive_lock_destroy (&NAME); \
486        }                                            \
487      while (0)
488 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
489 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
490 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
491 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
492
493 # endif
494
495 /* -------------------------- gl_once_t datatype -------------------------- */
496
497 typedef pthread_once_t gl_once_t;
498 # define gl_once_define(STORAGECLASS, NAME) \
499     STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
500 # define gl_once(NAME, INITFUNCTION) \
501     do                                                   \
502       {                                                  \
503         if (pthread_in_use ())                           \
504           {                                              \
505             if (pthread_once (&NAME, INITFUNCTION) != 0) \
506               abort ();                                  \
507           }                                              \
508         else                                             \
509           {                                              \
510             if (glthread_once_singlethreaded (&NAME))    \
511               INITFUNCTION ();                           \
512           }                                              \
513       }                                                  \
514     while (0)
515 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
516
517 # ifdef __cplusplus
518 }
519 # endif
520
521 #endif
522
523 /* ========================================================================= */
524
525 #if USE_PTH_THREADS
526
527 /* Use the GNU Pth threads library.  */
528
529 # include <pth.h>
530 # include <stdlib.h>
531
532 # ifdef __cplusplus
533 extern "C" {
534 # endif
535
536 # if USE_PTH_THREADS_WEAK
537
538 /* Use weak references to the GNU Pth threads library.  */
539
540 #  pragma weak pth_mutex_init
541 #  pragma weak pth_mutex_acquire
542 #  pragma weak pth_mutex_release
543 #  pragma weak pth_rwlock_init
544 #  pragma weak pth_rwlock_acquire
545 #  pragma weak pth_rwlock_release
546 #  pragma weak pth_once
547
548 #  pragma weak pth_cancel
549 #  define pth_in_use() (pth_cancel != NULL)
550
551 # else
552
553 #  define pth_in_use() 1
554
555 # endif
556
557 /* -------------------------- gl_lock_t datatype -------------------------- */
558
559 typedef pth_mutex_t gl_lock_t;
560 # define gl_lock_define(STORAGECLASS, NAME) \
561     STORAGECLASS pth_mutex_t NAME;
562 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
563     STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
564 # define gl_lock_initializer \
565     PTH_MUTEX_INIT
566 # define gl_lock_init(NAME) \
567     do                                               \
568       {                                              \
569         if (pth_in_use() && !pth_mutex_init (&NAME)) \
570           abort ();                                  \
571       }                                              \
572     while (0)
573 # define gl_lock_lock(NAME) \
574     do                                                           \
575       {                                                          \
576         if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) \
577           abort ();                                              \
578       }                                                          \
579     while (0)
580 # define gl_lock_unlock(NAME) \
581     do                                                  \
582       {                                                 \
583         if (pth_in_use() && !pth_mutex_release (&NAME)) \
584           abort ();                                     \
585       }                                                 \
586     while (0)
587 # define gl_lock_destroy(NAME) \
588     (void)(&NAME)
589
590 /* ------------------------- gl_rwlock_t datatype ------------------------- */
591
592 typedef pth_rwlock_t gl_rwlock_t;
593 #  define gl_rwlock_define(STORAGECLASS, NAME) \
594      STORAGECLASS pth_rwlock_t NAME;
595 #  define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
596      STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
597 #  define gl_rwlock_initializer \
598      PTH_RWLOCK_INIT
599 #  define gl_rwlock_init(NAME) \
600      do                                                \
601        {                                               \
602          if (pth_in_use() && !pth_rwlock_init (&NAME)) \
603            abort ();                                   \
604        }                                               \
605      while (0)
606 #  define gl_rwlock_rdlock(NAME) \
607      do                                                              \
608        {                                                             \
609          if (pth_in_use()                                            \
610              && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) \
611            abort ();                                                 \
612        }                                                             \
613      while (0)
614 #  define gl_rwlock_wrlock(NAME) \
615      do                                                              \
616        {                                                             \
617          if (pth_in_use()                                            \
618              && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) \
619            abort ();                                                 \
620        }                                                             \
621      while (0)
622 #  define gl_rwlock_unlock(NAME) \
623      do                                                   \
624        {                                                  \
625          if (pth_in_use() && !pth_rwlock_release (&NAME)) \
626            abort ();                                      \
627        }                                                  \
628      while (0)
629 #  define gl_rwlock_destroy(NAME) \
630      (void)(&NAME)
631
632 /* --------------------- gl_recursive_lock_t datatype --------------------- */
633
634 /* In Pth, mutexes are recursive by default.  */
635 typedef pth_mutex_t gl_recursive_lock_t;
636 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
637      STORAGECLASS pth_mutex_t NAME;
638 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
639      STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
640 #  define gl_recursive_lock_initializer \
641      PTH_MUTEX_INIT
642 #  define gl_recursive_lock_init(NAME) \
643      do                                               \
644        {                                              \
645          if (pth_in_use() && !pth_mutex_init (&NAME)) \
646            abort ();                                  \
647        }                                              \
648      while (0)
649 #  define gl_recursive_lock_lock(NAME) \
650      do                                                           \
651        {                                                          \
652          if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) \
653            abort ();                                              \
654        }                                                          \
655      while (0)
656 #  define gl_recursive_lock_unlock(NAME) \
657      do                                                  \
658        {                                                 \
659          if (pth_in_use() && !pth_mutex_release (&NAME)) \
660            abort ();                                     \
661        }                                                 \
662      while (0)
663 #  define gl_recursive_lock_destroy(NAME) \
664      (void)(&NAME)
665
666 /* -------------------------- gl_once_t datatype -------------------------- */
667
668 typedef pth_once_t gl_once_t;
669 # define gl_once_define(STORAGECLASS, NAME) \
670     STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
671 # define gl_once(NAME, INITFUNCTION) \
672     do                                                                \
673       {                                                               \
674         if (pth_in_use ())                                            \
675           {                                                           \
676             void (*gl_once_temp) (void) = INITFUNCTION;               \
677             if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
678               abort ();                                               \
679           }                                                           \
680         else                                                          \
681           {                                                           \
682             if (glthread_once_singlethreaded (&NAME))                 \
683               INITFUNCTION ();                                        \
684           }                                                           \
685       }                                                               \
686     while (0)
687 extern void glthread_once_call (void *arg);
688 extern int glthread_once_singlethreaded (pth_once_t *once_control);
689
690 # ifdef __cplusplus
691 }
692 # endif
693
694 #endif
695
696 /* ========================================================================= */
697
698 #if USE_SOLARIS_THREADS
699
700 /* Use the old Solaris threads library.  */
701
702 # include <thread.h>
703 # include <synch.h>
704 # include <stdlib.h>
705
706 # ifdef __cplusplus
707 extern "C" {
708 # endif
709
710 # if USE_SOLARIS_THREADS_WEAK
711
712 /* Use weak references to the old Solaris threads library.  */
713
714 #  pragma weak mutex_init
715 #  pragma weak mutex_lock
716 #  pragma weak mutex_unlock
717 #  pragma weak mutex_destroy
718 #  pragma weak rwlock_init
719 #  pragma weak rw_rdlock
720 #  pragma weak rw_wrlock
721 #  pragma weak rw_unlock
722 #  pragma weak rwlock_destroy
723 #  pragma weak thr_self
724
725 #  pragma weak thr_suspend
726 #  define thread_in_use() (thr_suspend != NULL)
727
728 # else
729
730 #  define thread_in_use() 1
731
732 # endif
733
734 /* -------------------------- gl_lock_t datatype -------------------------- */
735
736 typedef mutex_t gl_lock_t;
737 # define gl_lock_define(STORAGECLASS, NAME) \
738     STORAGECLASS mutex_t NAME;
739 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
740     STORAGECLASS mutex_t NAME = gl_lock_initializer;
741 # define gl_lock_initializer \
742     DEFAULTMUTEX
743 # define gl_lock_init(NAME) \
744     do                                                                       \
745       {                                                                      \
746         if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) \
747           abort ();                                                          \
748       }                                                                      \
749     while (0)
750 # define gl_lock_lock(NAME) \
751     do                                                   \
752       {                                                  \
753         if (thread_in_use () && mutex_lock (&NAME) != 0) \
754           abort ();                                      \
755       }                                                  \
756     while (0)
757 # define gl_lock_unlock(NAME) \
758     do                                                     \
759       {                                                    \
760         if (thread_in_use () && mutex_unlock (&NAME) != 0) \
761           abort ();                                        \
762       }                                                    \
763     while (0)
764 # define gl_lock_destroy(NAME) \
765     do                                                      \
766       {                                                     \
767         if (thread_in_use () && mutex_destroy (&NAME) != 0) \
768           abort ();                                         \
769       }                                                     \
770     while (0)
771
772 /* ------------------------- gl_rwlock_t datatype ------------------------- */
773
774 typedef rwlock_t gl_rwlock_t;
775 # define gl_rwlock_define(STORAGECLASS, NAME) \
776     STORAGECLASS rwlock_t NAME;
777 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
778     STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
779 # define gl_rwlock_initializer \
780     DEFAULTRWLOCK
781 # define gl_rwlock_init(NAME) \
782     do                                                                        \
783       {                                                                       \
784         if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) \
785           abort ();                                                           \
786       }                                                                       \
787     while (0)
788 # define gl_rwlock_rdlock(NAME) \
789     do                                                  \
790       {                                                 \
791         if (thread_in_use () && rw_rdlock (&NAME) != 0) \
792           abort ();                                     \
793       }                                                 \
794     while (0)
795 # define gl_rwlock_wrlock(NAME) \
796     do                                                  \
797       {                                                 \
798         if (thread_in_use () && rw_wrlock (&NAME) != 0) \
799           abort ();                                     \
800       }                                                 \
801     while (0)
802 # define gl_rwlock_unlock(NAME) \
803     do                                                  \
804       {                                                 \
805         if (thread_in_use () && rw_unlock (&NAME) != 0) \
806           abort ();                                     \
807       }                                                 \
808     while (0)
809 # define gl_rwlock_destroy(NAME) \
810     do                                                       \
811       {                                                      \
812         if (thread_in_use () && rwlock_destroy (&NAME) != 0) \
813           abort ();                                          \
814       }                                                      \
815     while (0)
816
817 /* --------------------- gl_recursive_lock_t datatype --------------------- */
818
819 /* Old Solaris threads did not have recursive locks.
820    We have to implement them ourselves.  */
821
822 typedef struct
823         {
824           mutex_t mutex;
825           thread_t owner;
826           unsigned long depth;
827         }
828         gl_recursive_lock_t;
829 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
830     STORAGECLASS gl_recursive_lock_t NAME;
831 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
832     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
833 # define gl_recursive_lock_initializer \
834     { DEFAULTMUTEX, (thread_t) 0, 0 }
835 # define gl_recursive_lock_init(NAME) \
836     do                                          \
837       {                                         \
838         if (thread_in_use ())                   \
839           glthread_recursive_lock_init (&NAME); \
840       }                                         \
841     while (0)
842 # define gl_recursive_lock_lock(NAME) \
843     do                                          \
844       {                                         \
845         if (thread_in_use ())                   \
846           glthread_recursive_lock_lock (&NAME); \
847       }                                         \
848     while (0)
849 # define gl_recursive_lock_unlock(NAME) \
850     do                                            \
851       {                                           \
852         if (thread_in_use ())                     \
853           glthread_recursive_lock_unlock (&NAME); \
854       }                                           \
855     while (0)
856 # define gl_recursive_lock_destroy(NAME) \
857     do                                             \
858       {                                            \
859         if (thread_in_use ())                      \
860           glthread_recursive_lock_destroy (&NAME); \
861       }                                            \
862     while (0)
863 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
864 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
865 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
866 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
867
868 /* -------------------------- gl_once_t datatype -------------------------- */
869
870 typedef struct
871         {
872           volatile int inited;
873           mutex_t mutex;
874         }
875         gl_once_t;
876 # define gl_once_define(STORAGECLASS, NAME) \
877     STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
878 # define gl_once(NAME, INITFUNCTION) \
879     do                                                \
880       {                                               \
881         if (thread_in_use ())                         \
882           {                                           \
883             glthread_once (&NAME, INITFUNCTION);      \
884           }                                           \
885         else                                          \
886           {                                           \
887             if (glthread_once_singlethreaded (&NAME)) \
888               INITFUNCTION ();                        \
889           }                                           \
890       }                                               \
891     while (0)
892 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
893 extern int glthread_once_singlethreaded (gl_once_t *once_control);
894
895 # ifdef __cplusplus
896 }
897 # endif
898
899 #endif
900
901 /* ========================================================================= */
902
903 #if USE_WIN32_THREADS
904
905 # include <windows.h>
906
907 # ifdef __cplusplus
908 extern "C" {
909 # endif
910
911 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
912    Semaphore types, because
913      - we need only to synchronize inside a single process (address space),
914        not inter-process locking,
915      - we don't need to support trylock operations.  (TryEnterCriticalSection
916        does not work on Windows 95/98/ME.  Packages that need trylock usually
917        define their own mutex type.)  */
918
919 /* There is no way to statically initialize a CRITICAL_SECTION.  It needs
920    to be done lazily, once only.  For this we need spinlocks.  */
921
922 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
923
924 /* -------------------------- gl_lock_t datatype -------------------------- */
925
926 typedef struct
927         {
928           gl_spinlock_t guard; /* protects the initialization */
929           CRITICAL_SECTION lock;
930         }
931         gl_lock_t;
932 # define gl_lock_define(STORAGECLASS, NAME) \
933     STORAGECLASS gl_lock_t NAME;
934 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
935     STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
936 # define gl_lock_initializer \
937     { { 0, -1 } }
938 # define gl_lock_init(NAME) \
939     glthread_lock_init (&NAME)
940 # define gl_lock_lock(NAME) \
941     glthread_lock_lock (&NAME)
942 # define gl_lock_unlock(NAME) \
943     glthread_lock_unlock (&NAME)
944 # define gl_lock_destroy(NAME) \
945     glthread_lock_destroy (&NAME)
946 extern void glthread_lock_init (gl_lock_t *lock);
947 extern void glthread_lock_lock (gl_lock_t *lock);
948 extern void glthread_lock_unlock (gl_lock_t *lock);
949 extern void glthread_lock_destroy (gl_lock_t *lock);
950
951 /* ------------------------- gl_rwlock_t datatype ------------------------- */
952
953 /* It is impossible to implement read-write locks using plain locks, without
954    introducing an extra thread dedicated to managing read-write locks.
955    Therefore here we need to use the low-level Event type.  */
956
957 typedef struct
958         {
959           HANDLE *array; /* array of waiting threads, each represented by an event */
960           unsigned int count; /* number of waiting threads */
961           unsigned int alloc; /* length of allocated array */
962           unsigned int offset; /* index of first waiting thread in array */
963         }
964         gl_waitqueue_t;
965 typedef struct
966         {
967           gl_spinlock_t guard; /* protects the initialization */
968           CRITICAL_SECTION lock; /* protects the remaining fields */
969           gl_waitqueue_t waiting_readers; /* waiting readers */
970           gl_waitqueue_t waiting_writers; /* waiting writers */
971           int runcount; /* number of readers running, or -1 when a writer runs */
972         }
973         gl_rwlock_t;
974 # define gl_rwlock_define(STORAGECLASS, NAME) \
975     STORAGECLASS gl_rwlock_t NAME;
976 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
977     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
978 # define gl_rwlock_initializer \
979     { { 0, -1 } }
980 # define gl_rwlock_init(NAME) \
981     glthread_rwlock_init (&NAME)
982 # define gl_rwlock_rdlock(NAME) \
983     glthread_rwlock_rdlock (&NAME)
984 # define gl_rwlock_wrlock(NAME) \
985     glthread_rwlock_wrlock (&NAME)
986 # define gl_rwlock_unlock(NAME) \
987     glthread_rwlock_unlock (&NAME)
988 # define gl_rwlock_destroy(NAME) \
989     glthread_rwlock_destroy (&NAME)
990 extern void glthread_rwlock_init (gl_rwlock_t *lock);
991 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
992 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
993 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
994 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
995
996 /* --------------------- gl_recursive_lock_t datatype --------------------- */
997
998 /* The Win32 documentation says that CRITICAL_SECTION already implements a
999    recursive lock.  But we need not rely on it: It's easy to implement a
1000    recursive lock without this assumption.  */
1001
1002 typedef struct
1003         {
1004           gl_spinlock_t guard; /* protects the initialization */
1005           DWORD owner;
1006           unsigned long depth;
1007           CRITICAL_SECTION lock;
1008         }
1009         gl_recursive_lock_t;
1010 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
1011     STORAGECLASS gl_recursive_lock_t NAME;
1012 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
1013     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
1014 # define gl_recursive_lock_initializer \
1015     { { 0, -1 }, 0, 0 }
1016 # define gl_recursive_lock_init(NAME) \
1017     glthread_recursive_lock_init (&NAME)
1018 # define gl_recursive_lock_lock(NAME) \
1019     glthread_recursive_lock_lock (&NAME)
1020 # define gl_recursive_lock_unlock(NAME) \
1021     glthread_recursive_lock_unlock (&NAME)
1022 # define gl_recursive_lock_destroy(NAME) \
1023     glthread_recursive_lock_destroy (&NAME)
1024 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
1025 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
1026 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
1027 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
1028
1029 /* -------------------------- gl_once_t datatype -------------------------- */
1030
1031 typedef struct
1032         {
1033           volatile int inited;
1034           volatile long started;
1035           CRITICAL_SECTION lock;
1036         }
1037         gl_once_t;
1038 # define gl_once_define(STORAGECLASS, NAME) \
1039     STORAGECLASS gl_once_t NAME = { -1, -1 };
1040 # define gl_once(NAME, INITFUNCTION) \
1041     glthread_once (&NAME, INITFUNCTION)
1042 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
1043
1044 # ifdef __cplusplus
1045 }
1046 # endif
1047
1048 #endif
1049
1050 /* ========================================================================= */
1051
1052 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
1053
1054 /* Provide dummy implementation if threads are not supported.  */
1055
1056 /* -------------------------- gl_lock_t datatype -------------------------- */
1057
1058 typedef int gl_lock_t;
1059 # define gl_lock_define(STORAGECLASS, NAME)
1060 # define gl_lock_define_initialized(STORAGECLASS, NAME)
1061 # define gl_lock_init(NAME)
1062 # define gl_lock_lock(NAME)
1063 # define gl_lock_unlock(NAME)
1064
1065 /* ------------------------- gl_rwlock_t datatype ------------------------- */
1066
1067 typedef int gl_rwlock_t;
1068 # define gl_rwlock_define(STORAGECLASS, NAME)
1069 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
1070 # define gl_rwlock_init(NAME)
1071 # define gl_rwlock_rdlock(NAME)
1072 # define gl_rwlock_wrlock(NAME)
1073 # define gl_rwlock_unlock(NAME)
1074
1075 /* --------------------- gl_recursive_lock_t datatype --------------------- */
1076
1077 typedef int gl_recursive_lock_t;
1078 # define gl_recursive_lock_define(STORAGECLASS, NAME)
1079 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
1080 # define gl_recursive_lock_init(NAME)
1081 # define gl_recursive_lock_lock(NAME)
1082 # define gl_recursive_lock_unlock(NAME)
1083
1084 /* -------------------------- gl_once_t datatype -------------------------- */
1085
1086 typedef int gl_once_t;
1087 # define gl_once_define(STORAGECLASS, NAME) \
1088     STORAGECLASS gl_once_t NAME = 0;
1089 # define gl_once(NAME, INITFUNCTION) \
1090     do                       \
1091       {                      \
1092         if (NAME == 0)       \
1093           {                  \
1094             NAME = ~ 0;      \
1095             INITFUNCTION (); \
1096           }                  \
1097       }                      \
1098     while (0)
1099
1100 #endif
1101
1102 /* ========================================================================= */
1103
1104 #endif /* _LOCK_H */