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)
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,
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:
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:
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);
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);
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);
84 /* ========================================================================= */
88 /* Use the POSIX threads library. */
96 # if PTHREAD_IN_USE_DETECTION_HARD
98 /* The pthread_in_use() detection needs to be done at runtime. */
99 # define pthread_in_use() \
101 extern int glthread_in_use (void);
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
146 # pragma weak pthread_rwlockattr_destroy
147 # ifndef pthread_self
148 # pragma weak pthread_self
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)
164 # if !PTHREAD_IN_USE_DETECTION_HARD
165 # define pthread_in_use() 1
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
);
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)
225 pthread_mutex_t guard
; /* protects the initialization */
226 pthread_rwlock_t rwlock
; /* read-write lock */
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
);
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 */
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
);
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
303 # define gl_recursive_lock_initializer \
304 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
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
);
320 pthread_mutex_t recmutex
; /* recursive mutex */
321 pthread_mutex_t guard
; /* protects the initialization */
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
);
348 /* Old versions of POSIX threads on Solaris did not have recursive locks.
349 We have to implement them ourselves. */
353 pthread_mutex_t mutex
;
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
);
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) \
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
);
396 /* ========================================================================= */
400 /* Use the GNU Pth threads library. */
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)
425 # define pth_in_use() 1
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 \
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) \
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 \
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) \
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 */
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 \
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
);
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 \
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) \
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) \
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
);
543 /* ========================================================================= */
545 #if USE_SOLARIS_THREADS
547 /* Use the old Solaris threads library. */
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)
576 # define thread_in_use() 1
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 \
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 \
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. */
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 -------------------------- */
657 # define gl_once_define(STORAGECLASS, NAME) \
658 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
659 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
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
);
672 /* ========================================================================= */
674 #if USE_WINDOWS_THREADS
676 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
677 # include <windows.h>
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 -------------------------- */
700 gl_spinlock_t guard
; /* protects the initialization */
701 CRITICAL_SECTION lock
;
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 \
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. */
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
;
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 */
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 \
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. */
776 gl_spinlock_t guard
; /* protects the initialization */
779 CRITICAL_SECTION lock
;
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 \
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 -------------------------- */
806 volatile long started
;
807 CRITICAL_SECTION lock
;
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));
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)
869 /* ========================================================================= */
871 /* Macros with built-in error handling. */
873 /* -------------------------- gl_lock_t datatype -------------------------- */
875 #define gl_lock_init(NAME) \
878 if (glthread_lock_init (&NAME)) \
882 #define gl_lock_lock(NAME) \
885 if (glthread_lock_lock (&NAME)) \
889 #define gl_lock_unlock(NAME) \
892 if (glthread_lock_unlock (&NAME)) \
896 #define gl_lock_destroy(NAME) \
899 if (glthread_lock_destroy (&NAME)) \
904 /* ------------------------- gl_rwlock_t datatype ------------------------- */
906 #define gl_rwlock_init(NAME) \
909 if (glthread_rwlock_init (&NAME)) \
913 #define gl_rwlock_rdlock(NAME) \
916 if (glthread_rwlock_rdlock (&NAME)) \
920 #define gl_rwlock_wrlock(NAME) \
923 if (glthread_rwlock_wrlock (&NAME)) \
927 #define gl_rwlock_unlock(NAME) \
930 if (glthread_rwlock_unlock (&NAME)) \
934 #define gl_rwlock_destroy(NAME) \
937 if (glthread_rwlock_destroy (&NAME)) \
942 /* --------------------- gl_recursive_lock_t datatype --------------------- */
944 #define gl_recursive_lock_init(NAME) \
947 if (glthread_recursive_lock_init (&NAME)) \
951 #define gl_recursive_lock_lock(NAME) \
954 if (glthread_recursive_lock_lock (&NAME)) \
958 #define gl_recursive_lock_unlock(NAME) \
961 if (glthread_recursive_lock_unlock (&NAME)) \
965 #define gl_recursive_lock_destroy(NAME) \
968 if (glthread_recursive_lock_destroy (&NAME)) \
973 /* -------------------------- gl_once_t datatype -------------------------- */
975 #define gl_once(NAME, INITFUNCTION) \
978 if (glthread_once (&NAME, INITFUNCTION)) \
983 /* ========================================================================= */