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