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 */
980