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