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