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