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