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