update devspec.en_US/1.0.general.md.
[devspec.git] / devspec.en_US / project / recutils / lib / glthread / lock.h
blob22580aa83c187508de511e28d3973b89d46710a4
1 /* Locking in multithreaded situations.
2 Copyright (C) 2005-2019 Free Software Foundation, Inc.
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.
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.
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/>. */
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. */
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.
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);
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);
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);
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);
78 #ifndef _LOCK_H
79 #define _LOCK_H
81 #include <errno.h>
82 #include <stdlib.h>
84 /* ========================================================================= */
86 #if USE_POSIX_THREADS
88 /* Use the POSIX threads library. */
90 # include <pthread.h>
92 # ifdef __cplusplus
93 extern "C" {
94 # endif
96 # if PTHREAD_IN_USE_DETECTION_HARD
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);
103 # endif
105 # if USE_POSIX_THREADS_WEAK
107 /* Use weak references to the POSIX threads library. */
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. */
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. */
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
151 # if !PTHREAD_IN_USE_DETECTION_HARD
152 /* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols
153 can be used to determine whether libpthread is in use. These are:
154 pthread_mutexattr_gettype
155 pthread_rwlockattr_destroy
156 pthread_rwlockattr_init
158 # pragma weak pthread_mutexattr_gettype
159 # define pthread_in_use() (pthread_mutexattr_gettype != NULL)
160 # endif
162 # else
164 # if !PTHREAD_IN_USE_DETECTION_HARD
165 # define pthread_in_use() 1
166 # endif
168 # endif
170 /* -------------------------- gl_lock_t datatype -------------------------- */
172 typedef pthread_mutex_t gl_lock_t;
173 # define gl_lock_define(STORAGECLASS, NAME) \
174 STORAGECLASS pthread_mutex_t NAME;
175 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
176 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
177 # define gl_lock_initializer \
178 PTHREAD_MUTEX_INITIALIZER
179 # define glthread_lock_init(LOCK) \
180 (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
181 # define glthread_lock_lock(LOCK) \
182 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
183 # define glthread_lock_unlock(LOCK) \
184 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
185 # define glthread_lock_destroy(LOCK) \
186 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
188 /* ------------------------- gl_rwlock_t datatype ------------------------- */
190 # if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
192 # ifdef PTHREAD_RWLOCK_INITIALIZER
194 typedef pthread_rwlock_t gl_rwlock_t;
195 # define gl_rwlock_define(STORAGECLASS, NAME) \
196 STORAGECLASS pthread_rwlock_t NAME;
197 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
198 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
199 # if HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
200 # define gl_rwlock_initializer \
201 PTHREAD_RWLOCK_INITIALIZER
202 # define glthread_rwlock_init(LOCK) \
203 (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
204 # else /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
205 # define gl_rwlock_initializer \
206 PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
207 # define glthread_rwlock_init(LOCK) \
208 (pthread_in_use () ? glthread_rwlock_init_for_glibc (LOCK) : 0)
209 extern int glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock);
210 # endif
211 # define glthread_rwlock_rdlock(LOCK) \
212 (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
213 # define glthread_rwlock_wrlock(LOCK) \
214 (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
215 # define glthread_rwlock_unlock(LOCK) \
216 (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
217 # define glthread_rwlock_destroy(LOCK) \
218 (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
220 # else
222 typedef struct
224 int initialized;
225 pthread_mutex_t guard; /* protects the initialization */
226 pthread_rwlock_t rwlock; /* read-write lock */
228 gl_rwlock_t;
229 # define gl_rwlock_define(STORAGECLASS, NAME) \
230 STORAGECLASS gl_rwlock_t NAME;
231 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
232 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
233 # define gl_rwlock_initializer \
234 { 0, PTHREAD_MUTEX_INITIALIZER }
235 # define glthread_rwlock_init(LOCK) \
236 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
237 # define glthread_rwlock_rdlock(LOCK) \
238 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
239 # define glthread_rwlock_wrlock(LOCK) \
240 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
241 # define glthread_rwlock_unlock(LOCK) \
242 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
243 # define glthread_rwlock_destroy(LOCK) \
244 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
245 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
246 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
247 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
248 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
249 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
251 # endif
253 # else
255 typedef struct
257 pthread_mutex_t lock; /* protects the remaining fields */
258 pthread_cond_t waiting_readers; /* waiting readers */
259 pthread_cond_t waiting_writers; /* waiting writers */
260 unsigned int waiting_writers_count; /* number of waiting writers */
261 int runcount; /* number of readers running, or -1 when a writer runs */
263 gl_rwlock_t;
264 # define gl_rwlock_define(STORAGECLASS, NAME) \
265 STORAGECLASS gl_rwlock_t NAME;
266 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
267 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
268 # define gl_rwlock_initializer \
269 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
270 # define glthread_rwlock_init(LOCK) \
271 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
272 # define glthread_rwlock_rdlock(LOCK) \
273 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
274 # define glthread_rwlock_wrlock(LOCK) \
275 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
276 # define glthread_rwlock_unlock(LOCK) \
277 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
278 # define glthread_rwlock_destroy(LOCK) \
279 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
280 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
281 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
282 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
283 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
284 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
286 # endif
288 /* --------------------- gl_recursive_lock_t datatype --------------------- */
290 # if HAVE_PTHREAD_MUTEX_RECURSIVE
292 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
294 typedef pthread_mutex_t gl_recursive_lock_t;
295 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
296 STORAGECLASS pthread_mutex_t NAME;
297 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
298 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
299 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
300 # define gl_recursive_lock_initializer \
301 PTHREAD_RECURSIVE_MUTEX_INITIALIZER
302 # else
303 # define gl_recursive_lock_initializer \
304 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
305 # endif
306 # define glthread_recursive_lock_init(LOCK) \
307 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
308 # define glthread_recursive_lock_lock(LOCK) \
309 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
310 # define glthread_recursive_lock_unlock(LOCK) \
311 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
312 # define glthread_recursive_lock_destroy(LOCK) \
313 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
314 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
316 # else
318 typedef struct
320 pthread_mutex_t recmutex; /* recursive mutex */
321 pthread_mutex_t guard; /* protects the initialization */
322 int initialized;
324 gl_recursive_lock_t;
325 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
326 STORAGECLASS gl_recursive_lock_t NAME;
327 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
328 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
329 # define gl_recursive_lock_initializer \
330 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
331 # define glthread_recursive_lock_init(LOCK) \
332 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
333 # define glthread_recursive_lock_lock(LOCK) \
334 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
335 # define glthread_recursive_lock_unlock(LOCK) \
336 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
337 # define glthread_recursive_lock_destroy(LOCK) \
338 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
339 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
340 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
341 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
342 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
344 # endif
346 # else
348 /* Old versions of POSIX threads on Solaris did not have recursive locks.
349 We have to implement them ourselves. */
351 typedef struct
353 pthread_mutex_t mutex;
354 pthread_t owner;
355 unsigned long depth;
357 gl_recursive_lock_t;
358 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
359 STORAGECLASS gl_recursive_lock_t NAME;
360 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
361 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
362 # define gl_recursive_lock_initializer \
363 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
364 # define glthread_recursive_lock_init(LOCK) \
365 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
366 # define glthread_recursive_lock_lock(LOCK) \
367 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
368 # define glthread_recursive_lock_unlock(LOCK) \
369 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
370 # define glthread_recursive_lock_destroy(LOCK) \
371 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
372 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
373 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
374 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
375 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
377 # endif
379 /* -------------------------- gl_once_t datatype -------------------------- */
381 typedef pthread_once_t gl_once_t;
382 # define gl_once_define(STORAGECLASS, NAME) \
383 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
384 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
385 (pthread_in_use () \
386 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \
387 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
388 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
390 # ifdef __cplusplus
392 # endif
394 #endif
396 /* ========================================================================= */
398 #if USE_PTH_THREADS
400 /* Use the GNU Pth threads library. */
402 # include <pth.h>
404 # ifdef __cplusplus
405 extern "C" {
406 # endif
408 # if USE_PTH_THREADS_WEAK
410 /* Use weak references to the GNU Pth threads library. */
412 # pragma weak pth_mutex_init
413 # pragma weak pth_mutex_acquire
414 # pragma weak pth_mutex_release
415 # pragma weak pth_rwlock_init
416 # pragma weak pth_rwlock_acquire
417 # pragma weak pth_rwlock_release
418 # pragma weak pth_once
420 # pragma weak pth_cancel
421 # define pth_in_use() (pth_cancel != NULL)
423 # else
425 # define pth_in_use() 1
427 # endif
429 /* -------------------------- gl_lock_t datatype -------------------------- */
431 typedef pth_mutex_t gl_lock_t;
432 # define gl_lock_define(STORAGECLASS, NAME) \
433 STORAGECLASS pth_mutex_t NAME;
434 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
435 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
436 # define gl_lock_initializer \
437 PTH_MUTEX_INIT
438 # define glthread_lock_init(LOCK) \
439 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
440 # define glthread_lock_lock(LOCK) \
441 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
442 # define glthread_lock_unlock(LOCK) \
443 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
444 # define glthread_lock_destroy(LOCK) \
445 ((void)(LOCK), 0)
447 /* ------------------------- gl_rwlock_t datatype ------------------------- */
449 /* Pth pth_rwlock_acquire always prefers readers. No autoconf test so far. */
450 # if HAVE_PTH_RWLOCK_ACQUIRE_PREFER_WRITER
452 typedef pth_rwlock_t gl_rwlock_t;
453 # define gl_rwlock_define(STORAGECLASS, NAME) \
454 STORAGECLASS pth_rwlock_t NAME;
455 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
456 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
457 # define gl_rwlock_initializer \
458 PTH_RWLOCK_INIT
459 # define glthread_rwlock_init(LOCK) \
460 (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0)
461 # define glthread_rwlock_rdlock(LOCK) \
462 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0)
463 # define glthread_rwlock_wrlock(LOCK) \
464 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0)
465 # define glthread_rwlock_unlock(LOCK) \
466 (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0)
467 # define glthread_rwlock_destroy(LOCK) \
468 ((void)(LOCK), 0)
470 # else
472 typedef struct
474 int initialized;
475 pth_mutex_t lock; /* protects the remaining fields */
476 pth_cond_t waiting_readers; /* waiting readers */
477 pth_cond_t waiting_writers; /* waiting writers */
478 unsigned int waiting_writers_count; /* number of waiting writers */
479 int runcount; /* number of readers running, or -1 when a writer runs */
481 gl_rwlock_t;
482 # define gl_rwlock_define(STORAGECLASS, NAME) \
483 STORAGECLASS gl_rwlock_t NAME;
484 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
485 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
486 # define gl_rwlock_initializer \
487 { 0 }
488 # define glthread_rwlock_init(LOCK) \
489 (pth_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
490 # define glthread_rwlock_rdlock(LOCK) \
491 (pth_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
492 # define glthread_rwlock_wrlock(LOCK) \
493 (pth_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
494 # define glthread_rwlock_unlock(LOCK) \
495 (pth_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
496 # define glthread_rwlock_destroy(LOCK) \
497 (pth_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
498 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
499 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
500 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
501 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
502 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
504 # endif
506 /* --------------------- gl_recursive_lock_t datatype --------------------- */
508 /* In Pth, mutexes are recursive by default. */
509 typedef pth_mutex_t gl_recursive_lock_t;
510 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
511 STORAGECLASS pth_mutex_t NAME;
512 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
513 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
514 # define gl_recursive_lock_initializer \
515 PTH_MUTEX_INIT
516 # define glthread_recursive_lock_init(LOCK) \
517 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
518 # define glthread_recursive_lock_lock(LOCK) \
519 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
520 # define glthread_recursive_lock_unlock(LOCK) \
521 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
522 # define glthread_recursive_lock_destroy(LOCK) \
523 ((void)(LOCK), 0)
525 /* -------------------------- gl_once_t datatype -------------------------- */
527 typedef pth_once_t gl_once_t;
528 # define gl_once_define(STORAGECLASS, NAME) \
529 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
530 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
531 (pth_in_use () \
532 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
533 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
534 extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void));
535 extern int glthread_once_singlethreaded (pth_once_t *once_control);
537 # ifdef __cplusplus
539 # endif
541 #endif
543 /* ========================================================================= */
545 #if USE_SOLARIS_THREADS
547 /* Use the old Solaris threads library. */
549 # include <thread.h>
550 # include <synch.h>
552 # ifdef __cplusplus
553 extern "C" {
554 # endif
556 # if USE_SOLARIS_THREADS_WEAK
558 /* Use weak references to the old Solaris threads library. */
560 # pragma weak mutex_init
561 # pragma weak mutex_lock
562 # pragma weak mutex_unlock
563 # pragma weak mutex_destroy
564 # pragma weak rwlock_init
565 # pragma weak rw_rdlock
566 # pragma weak rw_wrlock
567 # pragma weak rw_unlock
568 # pragma weak rwlock_destroy
569 # pragma weak thr_self
571 # pragma weak thr_suspend
572 # define thread_in_use() (thr_suspend != NULL)
574 # else
576 # define thread_in_use() 1
578 # endif
580 /* -------------------------- gl_lock_t datatype -------------------------- */
582 typedef mutex_t gl_lock_t;
583 # define gl_lock_define(STORAGECLASS, NAME) \
584 STORAGECLASS mutex_t NAME;
585 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
586 STORAGECLASS mutex_t NAME = gl_lock_initializer;
587 # define gl_lock_initializer \
588 DEFAULTMUTEX
589 # define glthread_lock_init(LOCK) \
590 (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
591 # define glthread_lock_lock(LOCK) \
592 (thread_in_use () ? mutex_lock (LOCK) : 0)
593 # define glthread_lock_unlock(LOCK) \
594 (thread_in_use () ? mutex_unlock (LOCK) : 0)
595 # define glthread_lock_destroy(LOCK) \
596 (thread_in_use () ? mutex_destroy (LOCK) : 0)
598 /* ------------------------- gl_rwlock_t datatype ------------------------- */
600 typedef rwlock_t gl_rwlock_t;
601 # define gl_rwlock_define(STORAGECLASS, NAME) \
602 STORAGECLASS rwlock_t NAME;
603 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
604 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
605 # define gl_rwlock_initializer \
606 DEFAULTRWLOCK
607 # define glthread_rwlock_init(LOCK) \
608 (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
609 # define glthread_rwlock_rdlock(LOCK) \
610 (thread_in_use () ? rw_rdlock (LOCK) : 0)
611 # define glthread_rwlock_wrlock(LOCK) \
612 (thread_in_use () ? rw_wrlock (LOCK) : 0)
613 # define glthread_rwlock_unlock(LOCK) \
614 (thread_in_use () ? rw_unlock (LOCK) : 0)
615 # define glthread_rwlock_destroy(LOCK) \
616 (thread_in_use () ? rwlock_destroy (LOCK) : 0)
618 /* --------------------- gl_recursive_lock_t datatype --------------------- */
620 /* Old Solaris threads did not have recursive locks.
621 We have to implement them ourselves. */
623 typedef struct
625 mutex_t mutex;
626 thread_t owner;
627 unsigned long depth;
629 gl_recursive_lock_t;
630 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
631 STORAGECLASS gl_recursive_lock_t NAME;
632 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
633 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
634 # define gl_recursive_lock_initializer \
635 { DEFAULTMUTEX, (thread_t) 0, 0 }
636 # define glthread_recursive_lock_init(LOCK) \
637 (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
638 # define glthread_recursive_lock_lock(LOCK) \
639 (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
640 # define glthread_recursive_lock_unlock(LOCK) \
641 (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
642 # define glthread_recursive_lock_destroy(LOCK) \
643 (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
644 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
645 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
646 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
647 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
649 /* -------------------------- gl_once_t datatype -------------------------- */
651 typedef struct
653 volatile int inited;
654 mutex_t mutex;
656 gl_once_t;
657 # define gl_once_define(STORAGECLASS, NAME) \
658 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
659 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
660 (thread_in_use () \
661 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
662 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
663 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
664 extern int glthread_once_singlethreaded (gl_once_t *once_control);
666 # ifdef __cplusplus
668 # endif
670 #endif
672 /* ========================================================================= */
674 #if USE_WINDOWS_THREADS
676 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
677 # include <windows.h>
679 # ifdef __cplusplus
680 extern "C" {
681 # endif
683 /* We can use CRITICAL_SECTION directly, rather than the native Windows Event,
684 Mutex, Semaphore types, because
685 - we need only to synchronize inside a single process (address space),
686 not inter-process locking,
687 - we don't need to support trylock operations. (TryEnterCriticalSection
688 does not work on Windows 95/98/ME. Packages that need trylock usually
689 define their own mutex type.) */
691 /* There is no way to statically initialize a CRITICAL_SECTION. It needs
692 to be done lazily, once only. For this we need spinlocks. */
694 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
696 /* -------------------------- gl_lock_t datatype -------------------------- */
698 typedef struct
700 gl_spinlock_t guard; /* protects the initialization */
701 CRITICAL_SECTION lock;
703 gl_lock_t;
704 # define gl_lock_define(STORAGECLASS, NAME) \
705 STORAGECLASS gl_lock_t NAME;
706 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
707 STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
708 # define gl_lock_initializer \
709 { { 0, -1 } }
710 # define glthread_lock_init(LOCK) \
711 (glthread_lock_init_func (LOCK), 0)
712 # define glthread_lock_lock(LOCK) \
713 glthread_lock_lock_func (LOCK)
714 # define glthread_lock_unlock(LOCK) \
715 glthread_lock_unlock_func (LOCK)
716 # define glthread_lock_destroy(LOCK) \
717 glthread_lock_destroy_func (LOCK)
718 extern void glthread_lock_init_func (gl_lock_t *lock);
719 extern int glthread_lock_lock_func (gl_lock_t *lock);
720 extern int glthread_lock_unlock_func (gl_lock_t *lock);
721 extern int glthread_lock_destroy_func (gl_lock_t *lock);
723 /* ------------------------- gl_rwlock_t datatype ------------------------- */
725 /* It is impossible to implement read-write locks using plain locks, without
726 introducing an extra thread dedicated to managing read-write locks.
727 Therefore here we need to use the low-level Event type. */
729 typedef struct
731 HANDLE *array; /* array of waiting threads, each represented by an event */
732 unsigned int count; /* number of waiting threads */
733 unsigned int alloc; /* length of allocated array */
734 unsigned int offset; /* index of first waiting thread in array */
736 gl_carray_waitqueue_t;
737 typedef struct
739 gl_spinlock_t guard; /* protects the initialization */
740 CRITICAL_SECTION lock; /* protects the remaining fields */
741 gl_carray_waitqueue_t waiting_readers; /* waiting readers */
742 gl_carray_waitqueue_t waiting_writers; /* waiting writers */
743 int runcount; /* number of readers running, or -1 when a writer runs */
745 gl_rwlock_t;
746 # define gl_rwlock_define(STORAGECLASS, NAME) \
747 STORAGECLASS gl_rwlock_t NAME;
748 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
749 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
750 # define gl_rwlock_initializer \
751 { { 0, -1 } }
752 # define glthread_rwlock_init(LOCK) \
753 (glthread_rwlock_init_func (LOCK), 0)
754 # define glthread_rwlock_rdlock(LOCK) \
755 glthread_rwlock_rdlock_func (LOCK)
756 # define glthread_rwlock_wrlock(LOCK) \
757 glthread_rwlock_wrlock_func (LOCK)
758 # define glthread_rwlock_unlock(LOCK) \
759 glthread_rwlock_unlock_func (LOCK)
760 # define glthread_rwlock_destroy(LOCK) \
761 glthread_rwlock_destroy_func (LOCK)
762 extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
763 extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock);
764 extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock);
765 extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock);
766 extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock);
768 /* --------------------- gl_recursive_lock_t datatype --------------------- */
770 /* The native Windows documentation says that CRITICAL_SECTION already
771 implements a recursive lock. But we need not rely on it: It's easy to
772 implement a recursive lock without this assumption. */
774 typedef struct
776 gl_spinlock_t guard; /* protects the initialization */
777 DWORD owner;
778 unsigned long depth;
779 CRITICAL_SECTION lock;
781 gl_recursive_lock_t;
782 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
783 STORAGECLASS gl_recursive_lock_t NAME;
784 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
785 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
786 # define gl_recursive_lock_initializer \
787 { { 0, -1 }, 0, 0 }
788 # define glthread_recursive_lock_init(LOCK) \
789 (glthread_recursive_lock_init_func (LOCK), 0)
790 # define glthread_recursive_lock_lock(LOCK) \
791 glthread_recursive_lock_lock_func (LOCK)
792 # define glthread_recursive_lock_unlock(LOCK) \
793 glthread_recursive_lock_unlock_func (LOCK)
794 # define glthread_recursive_lock_destroy(LOCK) \
795 glthread_recursive_lock_destroy_func (LOCK)
796 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
797 extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock);
798 extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock);
799 extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock);
801 /* -------------------------- gl_once_t datatype -------------------------- */
803 typedef struct
805 volatile int inited;
806 volatile long started;
807 CRITICAL_SECTION lock;
809 gl_once_t;
810 # define gl_once_define(STORAGECLASS, NAME) \
811 STORAGECLASS gl_once_t NAME = { -1, -1 };
812 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
813 (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
814 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
816 # ifdef __cplusplus
818 # endif
820 #endif
822 /* ========================================================================= */
824 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
826 /* Provide dummy implementation if threads are not supported. */
828 /* -------------------------- gl_lock_t datatype -------------------------- */
830 typedef int gl_lock_t;
831 # define gl_lock_define(STORAGECLASS, NAME)
832 # define gl_lock_define_initialized(STORAGECLASS, NAME)
833 # define glthread_lock_init(NAME) 0
834 # define glthread_lock_lock(NAME) 0
835 # define glthread_lock_unlock(NAME) 0
836 # define glthread_lock_destroy(NAME) 0
838 /* ------------------------- gl_rwlock_t datatype ------------------------- */
840 typedef int gl_rwlock_t;
841 # define gl_rwlock_define(STORAGECLASS, NAME)
842 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
843 # define glthread_rwlock_init(NAME) 0
844 # define glthread_rwlock_rdlock(NAME) 0
845 # define glthread_rwlock_wrlock(NAME) 0
846 # define glthread_rwlock_unlock(NAME) 0
847 # define glthread_rwlock_destroy(NAME) 0
849 /* --------------------- gl_recursive_lock_t datatype --------------------- */
851 typedef int gl_recursive_lock_t;
852 # define gl_recursive_lock_define(STORAGECLASS, NAME)
853 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
854 # define glthread_recursive_lock_init(NAME) 0
855 # define glthread_recursive_lock_lock(NAME) 0
856 # define glthread_recursive_lock_unlock(NAME) 0
857 # define glthread_recursive_lock_destroy(NAME) 0
859 /* -------------------------- gl_once_t datatype -------------------------- */
861 typedef int gl_once_t;
862 # define gl_once_define(STORAGECLASS, NAME) \
863 STORAGECLASS gl_once_t NAME = 0;
864 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
865 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
867 #endif
869 /* ========================================================================= */
871 /* Macros with built-in error handling. */
873 /* -------------------------- gl_lock_t datatype -------------------------- */
875 #define gl_lock_init(NAME) \
876 do \
878 if (glthread_lock_init (&NAME)) \
879 abort (); \
881 while (0)
882 #define gl_lock_lock(NAME) \
883 do \
885 if (glthread_lock_lock (&NAME)) \
886 abort (); \
888 while (0)
889 #define gl_lock_unlock(NAME) \
890 do \
892 if (glthread_lock_unlock (&NAME)) \
893 abort (); \
895 while (0)
896 #define gl_lock_destroy(NAME) \
897 do \
899 if (glthread_lock_destroy (&NAME)) \
900 abort (); \
902 while (0)
904 /* ------------------------- gl_rwlock_t datatype ------------------------- */
906 #define gl_rwlock_init(NAME) \
907 do \
909 if (glthread_rwlock_init (&NAME)) \
910 abort (); \
912 while (0)
913 #define gl_rwlock_rdlock(NAME) \
914 do \
916 if (glthread_rwlock_rdlock (&NAME)) \
917 abort (); \
919 while (0)
920 #define gl_rwlock_wrlock(NAME) \
921 do \
923 if (glthread_rwlock_wrlock (&NAME)) \
924 abort (); \
926 while (0)
927 #define gl_rwlock_unlock(NAME) \
928 do \
930 if (glthread_rwlock_unlock (&NAME)) \
931 abort (); \
933 while (0)
934 #define gl_rwlock_destroy(NAME) \
935 do \
937 if (glthread_rwlock_destroy (&NAME)) \
938 abort (); \
940 while (0)
942 /* --------------------- gl_recursive_lock_t datatype --------------------- */
944 #define gl_recursive_lock_init(NAME) \
945 do \
947 if (glthread_recursive_lock_init (&NAME)) \
948 abort (); \
950 while (0)
951 #define gl_recursive_lock_lock(NAME) \
952 do \
954 if (glthread_recursive_lock_lock (&NAME)) \
955 abort (); \
957 while (0)
958 #define gl_recursive_lock_unlock(NAME) \
959 do \
961 if (glthread_recursive_lock_unlock (&NAME)) \
962 abort (); \
964 while (0)
965 #define gl_recursive_lock_destroy(NAME) \
966 do \
968 if (glthread_recursive_lock_destroy (&NAME)) \
969 abort (); \
971 while (0)
973 /* -------------------------- gl_once_t datatype -------------------------- */
975 #define gl_once(NAME, INITFUNCTION) \
976 do \
978 if (glthread_once (&NAME, INITFUNCTION)) \
979 abort (); \
981 while (0)
983 /* ========================================================================= */
985 #endif /* _LOCK_H */