1 /* Locking in multithreaded situations.
2    Copyright (C) 2005-2006 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     if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
152 # define gl_lock_lock(NAME) \
153     if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
154 # define gl_lock_unlock(NAME) \
155     if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
156 # define gl_lock_destroy(NAME) \
157     if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
158 
159     /* ------------------------- gl_rwlock_t datatype ------------------------- */
160 
161 # if HAVE_PTHREAD_RWLOCK
162 
163 #  ifdef PTHREAD_RWLOCK_INITIALIZER
164 
165     typedef pthread_rwlock_t gl_rwlock_t;
166 #   define gl_rwlock_define(STORAGECLASS, NAME) \
167       STORAGECLASS pthread_rwlock_t NAME;
168 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
169       STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
170 #   define gl_rwlock_initializer \
171       PTHREAD_RWLOCK_INITIALIZER
172 #   define gl_rwlock_init(NAME) \
173       if (pthread_in_use () && pthread_rwlock_init (&NAME, NULL) != 0) abort ()
174 #   define gl_rwlock_rdlock(NAME) \
175       if (pthread_in_use () && pthread_rwlock_rdlock (&NAME) != 0) abort ()
176 #   define gl_rwlock_wrlock(NAME) \
177       if (pthread_in_use () && pthread_rwlock_wrlock (&NAME) != 0) abort ()
178 #   define gl_rwlock_unlock(NAME) \
179       if (pthread_in_use () && pthread_rwlock_unlock (&NAME) != 0) abort ()
180 #   define gl_rwlock_destroy(NAME) \
181       if (pthread_in_use () && pthread_rwlock_destroy (&NAME) != 0) abort ()
182 
183 #  else
184 
185     typedef struct
186     {
187         int initialized;
188         pthread_mutex_t guard;   /* protects the initialization */
189         pthread_rwlock_t rwlock; /* read-write lock */
190     }
191     gl_rwlock_t;
192 #   define gl_rwlock_define(STORAGECLASS, NAME) \
193       STORAGECLASS gl_rwlock_t NAME;
194 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
195       STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
196 #   define gl_rwlock_initializer \
197       { 0, PTHREAD_MUTEX_INITIALIZER }
198 #   define gl_rwlock_init(NAME) \
199       if (pthread_in_use ()) glthread_rwlock_init (&NAME)
200 #   define gl_rwlock_rdlock(NAME) \
201       if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
202 #   define gl_rwlock_wrlock(NAME) \
203       if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
204 #   define gl_rwlock_unlock(NAME) \
205       if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
206 #   define gl_rwlock_destroy(NAME) \
207       if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
208     extern void glthread_rwlock_init (gl_rwlock_t *lock);
209     extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
210     extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
211     extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
212     extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
213 
214 #  endif
215 
216 # else
217 
218     typedef struct
219     {
220         pthread_mutex_t lock; /* protects the remaining fields */
221         pthread_cond_t waiting_readers; /* waiting readers */
222         pthread_cond_t waiting_writers; /* waiting writers */
223         unsigned int waiting_writers_count; /* number of waiting writers */
224         int runcount; /* number of readers running, or -1 when a writer runs */
225     }
226     gl_rwlock_t;
227 # define gl_rwlock_define(STORAGECLASS, NAME) \
228     STORAGECLASS gl_rwlock_t NAME;
229 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
230     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
231 # define gl_rwlock_initializer \
232     { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
233 # define gl_rwlock_init(NAME) \
234     if (pthread_in_use ()) glthread_rwlock_init (&NAME)
235 # define gl_rwlock_rdlock(NAME) \
236     if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
237 # define gl_rwlock_wrlock(NAME) \
238     if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
239 # define gl_rwlock_unlock(NAME) \
240     if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
241 # define gl_rwlock_destroy(NAME) \
242     if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
243     extern void glthread_rwlock_init (gl_rwlock_t *lock);
244     extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
245     extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
246     extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
247     extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
248 
249 # endif
250 
251     /* --------------------- gl_recursive_lock_t datatype --------------------- */
252 
253 # if HAVE_PTHREAD_MUTEX_RECURSIVE
254 
255 #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
256 
257     typedef pthread_mutex_t gl_recursive_lock_t;
258 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
259       STORAGECLASS pthread_mutex_t NAME;
260 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
261       STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
262 #   ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
263 #    define gl_recursive_lock_initializer \
264        PTHREAD_RECURSIVE_MUTEX_INITIALIZER
265 #   else
266 #    define gl_recursive_lock_initializer \
267        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
268 #   endif
269 #   define gl_recursive_lock_init(NAME) \
270       if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
271 #   define gl_recursive_lock_lock(NAME) \
272       if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
273 #   define gl_recursive_lock_unlock(NAME) \
274       if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
275 #   define gl_recursive_lock_destroy(NAME) \
276       if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
277 
278 #  else
279 
280     typedef struct
281     {
282         pthread_mutex_t recmutex; /* recursive mutex */
283         pthread_mutex_t guard;    /* protects the initialization */
284         int initialized;
285     }
286     gl_recursive_lock_t;
287 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
288       STORAGECLASS gl_recursive_lock_t NAME;
289 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
290       STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
291 #   define gl_recursive_lock_initializer \
292       { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
293 #   define gl_recursive_lock_init(NAME) \
294       if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
295 #   define gl_recursive_lock_lock(NAME) \
296       if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
297 #   define gl_recursive_lock_unlock(NAME) \
298       if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
299 #   define gl_recursive_lock_destroy(NAME) \
300       if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
301     extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
302     extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
303     extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
304     extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
305 
306 #  endif
307 
308 # else
309 
310     /* Old versions of POSIX threads on Solaris did not have recursive locks.
311        We have to implement them ourselves.  */
312 
313     typedef struct
314     {
315         pthread_mutex_t mutex;
316         pthread_t owner;
317         unsigned long depth;
318     }
319     gl_recursive_lock_t;
320 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
321      STORAGECLASS gl_recursive_lock_t NAME;
322 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
323      STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
324 #  define gl_recursive_lock_initializer \
325      { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
326 #  define gl_recursive_lock_init(NAME) \
327      if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
328 #  define gl_recursive_lock_lock(NAME) \
329      if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
330 #  define gl_recursive_lock_unlock(NAME) \
331      if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
332 #  define gl_recursive_lock_destroy(NAME) \
333      if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
334     extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
335     extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
336     extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
337     extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
338 
339 # endif
340 
341     /* -------------------------- gl_once_t datatype -------------------------- */
342 
343     typedef pthread_once_t gl_once_t;
344 # define gl_once_define(STORAGECLASS, NAME) \
345     STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
346 # define gl_once(NAME, INITFUNCTION) \
347     do                                                   \
348       {                                                  \
349         if (pthread_in_use ())                           \
350           {                                              \
351             if (pthread_once (&NAME, INITFUNCTION) != 0) \
352               abort ();                                  \
353           }                                              \
354         else                                             \
355           {                                              \
356             if (glthread_once_singlethreaded (&NAME))    \
357               INITFUNCTION ();                           \
358           }                                              \
359       }                                                  \
360     while (0)
361     extern int glthread_once_singlethreaded (pthread_once_t *once_control);
362 
363 # ifdef __cplusplus
364 }
365 # endif
366 
367 #endif
368 
369 /* ========================================================================= */
370 
371 #if USE_PTH_THREADS
372 
373 /* Use the GNU Pth threads library.  */
374 
375 # include <pth.h>
376 # include <stdlib.h>
377 
378 # ifdef __cplusplus
379 extern "C" {
380 # endif
381 
382 # if USE_PTH_THREADS_WEAK
383 
384     /* Use weak references to the GNU Pth threads library.  */
385 
386 #  pragma weak pth_mutex_init
387 #  pragma weak pth_mutex_acquire
388 #  pragma weak pth_mutex_release
389 #  pragma weak pth_rwlock_init
390 #  pragma weak pth_rwlock_acquire
391 #  pragma weak pth_rwlock_release
392 #  pragma weak pth_once
393 
394 #  pragma weak pth_cancel
395 #  define pth_in_use() (pth_cancel != NULL)
396 
397 # else
398 
399 #  define pth_in_use() 1
400 
401 # endif
402 
403     /* -------------------------- gl_lock_t datatype -------------------------- */
404 
405     typedef pth_mutex_t gl_lock_t;
406 # define gl_lock_define(STORAGECLASS, NAME) \
407     STORAGECLASS pth_mutex_t NAME;
408 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
409     STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
410 # define gl_lock_initializer \
411     PTH_MUTEX_INIT
412 # define gl_lock_init(NAME) \
413     if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
414 # define gl_lock_lock(NAME) \
415     if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
416 # define gl_lock_unlock(NAME) \
417     if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
418 # define gl_lock_destroy(NAME) \
419     (void)(&NAME)
420 
421     /* ------------------------- gl_rwlock_t datatype ------------------------- */
422 
423     typedef pth_rwlock_t gl_rwlock_t;
424 #  define gl_rwlock_define(STORAGECLASS, NAME) \
425      STORAGECLASS pth_rwlock_t NAME;
426 #  define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
427      STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
428 #  define gl_rwlock_initializer \
429      PTH_RWLOCK_INIT
430 #  define gl_rwlock_init(NAME) \
431      if (pth_in_use() && !pth_rwlock_init (&NAME)) abort ()
432 #  define gl_rwlock_rdlock(NAME) \
433      if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) abort ()
434 #  define gl_rwlock_wrlock(NAME) \
435      if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) abort ()
436 #  define gl_rwlock_unlock(NAME) \
437      if (pth_in_use() && !pth_rwlock_release (&NAME)) abort ()
438 #  define gl_rwlock_destroy(NAME) \
439      (void)(&NAME)
440 
441     /* --------------------- gl_recursive_lock_t datatype --------------------- */
442 
443     /* In Pth, mutexes are recursive by default.  */
444     typedef pth_mutex_t gl_recursive_lock_t;
445 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
446      STORAGECLASS pth_mutex_t NAME;
447 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
448      STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
449 #  define gl_recursive_lock_initializer \
450      PTH_MUTEX_INIT
451 #  define gl_recursive_lock_init(NAME) \
452      if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
453 #  define gl_recursive_lock_lock(NAME) \
454      if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
455 #  define gl_recursive_lock_unlock(NAME) \
456      if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
457 #  define gl_recursive_lock_destroy(NAME) \
458      (void)(&NAME)
459 
460     /* -------------------------- gl_once_t datatype -------------------------- */
461 
462     typedef pth_once_t gl_once_t;
463 # define gl_once_define(STORAGECLASS, NAME) \
464     STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
465 # define gl_once(NAME, INITFUNCTION) \
466     do                                                                \
467       {                                                               \
468         if (pth_in_use ())                                            \
469           {                                                           \
470             void (*gl_once_temp) (void) = INITFUNCTION;               \
471             if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
472               abort ();                                               \
473           }                                                           \
474         else                                                          \
475           {                                                           \
476             if (glthread_once_singlethreaded (&NAME))                 \
477               INITFUNCTION ();                                        \
478           }                                                           \
479       }                                                               \
480     while (0)
481     extern void glthread_once_call (void *arg);
482     extern int glthread_once_singlethreaded (pth_once_t *once_control);
483 
484 # ifdef __cplusplus
485 }
486 # endif
487 
488 #endif
489 
490 /* ========================================================================= */
491 
492 #if USE_SOLARIS_THREADS
493 
494 /* Use the old Solaris threads library.  */
495 
496 # include <thread.h>
497 # include <synch.h>
498 # include <stdlib.h>
499 
500 # ifdef __cplusplus
501 extern "C" {
502 # endif
503 
504 # if USE_SOLARIS_THREADS_WEAK
505 
506     /* Use weak references to the old Solaris threads library.  */
507 
508 #  pragma weak mutex_init
509 #  pragma weak mutex_lock
510 #  pragma weak mutex_unlock
511 #  pragma weak mutex_destroy
512 #  pragma weak rwlock_init
513 #  pragma weak rw_rdlock
514 #  pragma weak rw_wrlock
515 #  pragma weak rw_unlock
516 #  pragma weak rwlock_destroy
517 #  pragma weak thr_self
518 
519 #  pragma weak thr_suspend
520 #  define thread_in_use() (thr_suspend != NULL)
521 
522 # else
523 
524 #  define thread_in_use() 1
525 
526 # endif
527 
528     /* -------------------------- gl_lock_t datatype -------------------------- */
529 
530     typedef mutex_t gl_lock_t;
531 # define gl_lock_define(STORAGECLASS, NAME) \
532     STORAGECLASS mutex_t NAME;
533 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
534     STORAGECLASS mutex_t NAME = gl_lock_initializer;
535 # define gl_lock_initializer \
536     DEFAULTMUTEX
537 # define gl_lock_init(NAME) \
538     if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
539 # define gl_lock_lock(NAME) \
540     if (thread_in_use () && mutex_lock (&NAME) != 0) abort ()
541 # define gl_lock_unlock(NAME) \
542     if (thread_in_use () && mutex_unlock (&NAME) != 0) abort ()
543 # define gl_lock_destroy(NAME) \
544     if (thread_in_use () && mutex_destroy (&NAME) != 0) abort ()
545 
546     /* ------------------------- gl_rwlock_t datatype ------------------------- */
547 
548     typedef rwlock_t gl_rwlock_t;
549 # define gl_rwlock_define(STORAGECLASS, NAME) \
550     STORAGECLASS rwlock_t NAME;
551 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
552     STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
553 # define gl_rwlock_initializer \
554     DEFAULTRWLOCK
555 # define gl_rwlock_init(NAME) \
556     if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
557 # define gl_rwlock_rdlock(NAME) \
558     if (thread_in_use () && rw_rdlock (&NAME) != 0) abort ()
559 # define gl_rwlock_wrlock(NAME) \
560     if (thread_in_use () && rw_wrlock (&NAME) != 0) abort ()
561 # define gl_rwlock_unlock(NAME) \
562     if (thread_in_use () && rw_unlock (&NAME) != 0) abort ()
563 # define gl_rwlock_destroy(NAME) \
564     if (thread_in_use () && rwlock_destroy (&NAME) != 0) abort ()
565 
566     /* --------------------- gl_recursive_lock_t datatype --------------------- */
567 
568     /* Old Solaris threads did not have recursive locks.
569        We have to implement them ourselves.  */
570 
571     typedef struct
572     {
573         mutex_t mutex;
574         thread_t owner;
575         unsigned long depth;
576     }
577     gl_recursive_lock_t;
578 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
579     STORAGECLASS gl_recursive_lock_t NAME;
580 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
581     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
582 # define gl_recursive_lock_initializer \
583     { DEFAULTMUTEX, (thread_t) 0, 0 }
584 # define gl_recursive_lock_init(NAME) \
585     if (thread_in_use ()) glthread_recursive_lock_init (&NAME)
586 # define gl_recursive_lock_lock(NAME) \
587     if (thread_in_use ()) glthread_recursive_lock_lock (&NAME)
588 # define gl_recursive_lock_unlock(NAME) \
589     if (thread_in_use ()) glthread_recursive_lock_unlock (&NAME)
590 # define gl_recursive_lock_destroy(NAME) \
591     if (thread_in_use ()) glthread_recursive_lock_destroy (&NAME)
592     extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
593     extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
594     extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
595     extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
596 
597     /* -------------------------- gl_once_t datatype -------------------------- */
598 
599     typedef struct
600     {
601         volatile int inited;
602         mutex_t mutex;
603     }
604     gl_once_t;
605 # define gl_once_define(STORAGECLASS, NAME) \
606     STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
607 # define gl_once(NAME, INITFUNCTION) \
608     do                                                \
609       {                                               \
610         if (thread_in_use ())                         \
611           {                                           \
612             glthread_once (&NAME, INITFUNCTION);      \
613           }                                           \
614         else                                          \
615           {                                           \
616             if (glthread_once_singlethreaded (&NAME)) \
617               INITFUNCTION ();                        \
618           }                                           \
619       }                                               \
620     while (0)
621     extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
622     extern int glthread_once_singlethreaded (gl_once_t *once_control);
623 
624 # ifdef __cplusplus
625 }
626 # endif
627 
628 #endif
629 
630 /* ========================================================================= */
631 
632 #if USE_WIN32_THREADS
633 
634 # include <windows.h>
635 
636 # ifdef __cplusplus
637 extern "C" {
638 # endif
639 
640     /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
641        Semaphore types, because
642          - we need only to synchronize inside a single process (address space),
643            not inter-process locking,
644          - we don't need to support trylock operations.  (TryEnterCriticalSection
645            does not work on Windows 95/98/ME.  Packages that need trylock usually
646            define their own mutex type.)  */
647 
648     /* There is no way to statically initialize a CRITICAL_SECTION.  It needs
649        to be done lazily, once only.  For this we need spinlocks.  */
650 
651     typedef struct
652     {
653         volatile int done;
654         volatile long started;
655     } gl_spinlock_t;
656 
657     /* -------------------------- gl_lock_t datatype -------------------------- */
658 
659     typedef struct
660     {
661         gl_spinlock_t guard; /* protects the initialization */
662         CRITICAL_SECTION lock;
663     }
664     gl_lock_t;
665 # define gl_lock_define(STORAGECLASS, NAME) \
666     STORAGECLASS gl_lock_t NAME;
667 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
668     STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
669 # define gl_lock_initializer \
670     { { 0, -1 } }
671 # define gl_lock_init(NAME) \
672     glthread_lock_init (&NAME)
673 # define gl_lock_lock(NAME) \
674     glthread_lock_lock (&NAME)
675 # define gl_lock_unlock(NAME) \
676     glthread_lock_unlock (&NAME)
677 # define gl_lock_destroy(NAME) \
678     glthread_lock_destroy (&NAME)
679     extern void glthread_lock_init (gl_lock_t *lock);
680     extern void glthread_lock_lock (gl_lock_t *lock);
681     extern void glthread_lock_unlock (gl_lock_t *lock);
682     extern void glthread_lock_destroy (gl_lock_t *lock);
683 
684     /* ------------------------- gl_rwlock_t datatype ------------------------- */
685 
686     /* It is impossible to implement read-write locks using plain locks, without
687        introducing an extra thread dedicated to managing read-write locks.
688        Therefore here we need to use the low-level Event type.  */
689 
690     typedef struct
691     {
692         HANDLE *array; /* array of waiting threads, each represented by an event */
693         unsigned int count; /* number of waiting threads */
694         unsigned int alloc; /* length of allocated array */
695         unsigned int offset; /* index of first waiting thread in array */
696     }
697     gl_waitqueue_t;
698     typedef struct
699     {
700         gl_spinlock_t guard; /* protects the initialization */
701         CRITICAL_SECTION lock; /* protects the remaining fields */
702         gl_waitqueue_t waiting_readers; /* waiting readers */
703         gl_waitqueue_t waiting_writers; /* waiting writers */
704         int runcount; /* number of readers running, or -1 when a writer runs */
705     }
706     gl_rwlock_t;
707 # define gl_rwlock_define(STORAGECLASS, NAME) \
708     STORAGECLASS gl_rwlock_t NAME;
709 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
710     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
711 # define gl_rwlock_initializer \
712     { { 0, -1 } }
713 # define gl_rwlock_init(NAME) \
714     glthread_rwlock_init (&NAME)
715 # define gl_rwlock_rdlock(NAME) \
716     glthread_rwlock_rdlock (&NAME)
717 # define gl_rwlock_wrlock(NAME) \
718     glthread_rwlock_wrlock (&NAME)
719 # define gl_rwlock_unlock(NAME) \
720     glthread_rwlock_unlock (&NAME)
721 # define gl_rwlock_destroy(NAME) \
722     glthread_rwlock_destroy (&NAME)
723     extern void glthread_rwlock_init (gl_rwlock_t *lock);
724     extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
725     extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
726     extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
727     extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
728 
729     /* --------------------- gl_recursive_lock_t datatype --------------------- */
730 
731     /* The Win32 documentation says that CRITICAL_SECTION already implements a
732        recursive lock.  But we need not rely on it: It's easy to implement a
733        recursive lock without this assumption.  */
734 
735     typedef struct
736     {
737         gl_spinlock_t guard; /* protects the initialization */
738         DWORD owner;
739         unsigned long depth;
740         CRITICAL_SECTION lock;
741     }
742     gl_recursive_lock_t;
743 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
744     STORAGECLASS gl_recursive_lock_t NAME;
745 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
746     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
747 # define gl_recursive_lock_initializer \
748     { { 0, -1 }, 0, 0 }
749 # define gl_recursive_lock_init(NAME) \
750     glthread_recursive_lock_init (&NAME)
751 # define gl_recursive_lock_lock(NAME) \
752     glthread_recursive_lock_lock (&NAME)
753 # define gl_recursive_lock_unlock(NAME) \
754     glthread_recursive_lock_unlock (&NAME)
755 # define gl_recursive_lock_destroy(NAME) \
756     glthread_recursive_lock_destroy (&NAME)
757     extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
758     extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
759     extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
760     extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
761 
762     /* -------------------------- gl_once_t datatype -------------------------- */
763 
764     typedef struct
765     {
766         volatile int inited;
767         volatile long started;
768         CRITICAL_SECTION lock;
769     }
770     gl_once_t;
771 # define gl_once_define(STORAGECLASS, NAME) \
772     STORAGECLASS gl_once_t NAME = { -1, -1 };
773 # define gl_once(NAME, INITFUNCTION) \
774     glthread_once (&NAME, INITFUNCTION)
775     extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
776 
777 # ifdef __cplusplus
778 }
779 # endif
780 
781 #endif
782 
783 /* ========================================================================= */
784 
785 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
786 
787 /* Provide dummy implementation if threads are not supported.  */
788 
789 /* -------------------------- gl_lock_t datatype -------------------------- */
790 
791 typedef int gl_lock_t;
792 # define gl_lock_define(STORAGECLASS, NAME)
793 # define gl_lock_define_initialized(STORAGECLASS, NAME)
794 # define gl_lock_init(NAME)
795 # define gl_lock_lock(NAME)
796 # define gl_lock_unlock(NAME)
797 
798 /* ------------------------- gl_rwlock_t datatype ------------------------- */
799 
800 typedef int gl_rwlock_t;
801 # define gl_rwlock_define(STORAGECLASS, NAME)
802 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
803 # define gl_rwlock_init(NAME)
804 # define gl_rwlock_rdlock(NAME)
805 # define gl_rwlock_wrlock(NAME)
806 # define gl_rwlock_unlock(NAME)
807 
808 /* --------------------- gl_recursive_lock_t datatype --------------------- */
809 
810 typedef int gl_recursive_lock_t;
811 # define gl_recursive_lock_define(STORAGECLASS, NAME)
812 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
813 # define gl_recursive_lock_init(NAME)
814 # define gl_recursive_lock_lock(NAME)
815 # define gl_recursive_lock_unlock(NAME)
816 
817 /* -------------------------- gl_once_t datatype -------------------------- */
818 
819 typedef int gl_once_t;
820 # define gl_once_define(STORAGECLASS, NAME) \
821     STORAGECLASS gl_once_t NAME = 0;
822 # define gl_once(NAME, INITFUNCTION) \
823     do                       \
824       {                      \
825         if (NAME == 0)       \
826           {                  \
827             NAME = ~ 0;      \
828             INITFUNCTION (); \
829           }                  \
830       }                      \
831     while (0)
832 
833 #endif
834 
835 /* ========================================================================= */
836 
837 #endif /* _LOCK_H */
838