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