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