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