1 /* Locking in multithreaded situations.
2 Copyright (C) 2005-2018 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 # pragma weak pthread_cancel
153 # define pthread_in_use() (pthread_cancel != NULL)
158 # if !PTHREAD_IN_USE_DETECTION_HARD
159 # define pthread_in_use() 1
164 /* -------------------------- gl_lock_t datatype -------------------------- */
166 typedef pthread_mutex_t gl_lock_t;
167 # define gl_lock_define(STORAGECLASS, NAME) \
168 STORAGECLASS pthread_mutex_t NAME;
169 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
170 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
171 # define gl_lock_initializer \
172 PTHREAD_MUTEX_INITIALIZER
173 # define glthread_lock_init(LOCK) \
174 (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
175 # define glthread_lock_lock(LOCK) \
176 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
177 # define glthread_lock_unlock(LOCK) \
178 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
179 # define glthread_lock_destroy(LOCK) \
180 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
182 /* ------------------------- gl_rwlock_t datatype ------------------------- */
184 # if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
186 # ifdef PTHREAD_RWLOCK_INITIALIZER
188 typedef pthread_rwlock_t gl_rwlock_t;
189 # define gl_rwlock_define(STORAGECLASS, NAME) \
190 STORAGECLASS pthread_rwlock_t NAME;
191 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
192 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
193 # if HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
194 # define gl_rwlock_initializer \
195 PTHREAD_RWLOCK_INITIALIZER
196 # define glthread_rwlock_init(LOCK) \
197 (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
198 # else /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
199 # define gl_rwlock_initializer \
200 PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
201 # define glthread_rwlock_init(LOCK) \
202 (pthread_in_use () ? glthread_rwlock_init_for_glibc (LOCK) : 0)
203 extern int glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock);
205 # define glthread_rwlock_rdlock(LOCK) \
206 (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
207 # define glthread_rwlock_wrlock(LOCK) \
208 (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
209 # define glthread_rwlock_unlock(LOCK) \
210 (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
211 # define glthread_rwlock_destroy(LOCK) \
212 (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
219 pthread_mutex_t guard; /* protects the initialization */
220 pthread_rwlock_t rwlock; /* read-write lock */
223 # define gl_rwlock_define(STORAGECLASS, NAME) \
224 STORAGECLASS gl_rwlock_t NAME;
225 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
226 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
227 # define gl_rwlock_initializer \
228 { 0, PTHREAD_MUTEX_INITIALIZER }
229 # define glthread_rwlock_init(LOCK) \
230 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
231 # define glthread_rwlock_rdlock(LOCK) \
232 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
233 # define glthread_rwlock_wrlock(LOCK) \
234 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
235 # define glthread_rwlock_unlock(LOCK) \
236 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
237 # define glthread_rwlock_destroy(LOCK) \
238 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
239 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
240 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
241 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
242 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
243 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
251 pthread_mutex_t lock; /* protects the remaining fields */
252 pthread_cond_t waiting_readers; /* waiting readers */
253 pthread_cond_t waiting_writers; /* waiting writers */
254 unsigned int waiting_writers_count; /* number of waiting writers */
255 int runcount; /* number of readers running, or -1 when a writer runs */
258 # define gl_rwlock_define(STORAGECLASS, NAME) \
259 STORAGECLASS gl_rwlock_t NAME;
260 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
261 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
262 # define gl_rwlock_initializer \
263 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
264 # define glthread_rwlock_init(LOCK) \
265 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
266 # define glthread_rwlock_rdlock(LOCK) \
267 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
268 # define glthread_rwlock_wrlock(LOCK) \
269 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
270 # define glthread_rwlock_unlock(LOCK) \
271 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
272 # define glthread_rwlock_destroy(LOCK) \
273 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
274 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
275 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
276 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
277 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
278 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
282 /* --------------------- gl_recursive_lock_t datatype --------------------- */
284 # if HAVE_PTHREAD_MUTEX_RECURSIVE
286 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
288 typedef pthread_mutex_t gl_recursive_lock_t;
289 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
290 STORAGECLASS pthread_mutex_t NAME;
291 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
292 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
293 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
294 # define gl_recursive_lock_initializer \
295 PTHREAD_RECURSIVE_MUTEX_INITIALIZER
297 # define gl_recursive_lock_initializer \
298 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
300 # define glthread_recursive_lock_init(LOCK) \
301 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
302 # define glthread_recursive_lock_lock(LOCK) \
303 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
304 # define glthread_recursive_lock_unlock(LOCK) \
305 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
306 # define glthread_recursive_lock_destroy(LOCK) \
307 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
308 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
314 pthread_mutex_t recmutex; /* recursive mutex */
315 pthread_mutex_t guard; /* protects the initialization */
319 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
320 STORAGECLASS gl_recursive_lock_t NAME;
321 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
322 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
323 # define gl_recursive_lock_initializer \
324 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
325 # define glthread_recursive_lock_init(LOCK) \
326 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
327 # define glthread_recursive_lock_lock(LOCK) \
328 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
329 # define glthread_recursive_lock_unlock(LOCK) \
330 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
331 # define glthread_recursive_lock_destroy(LOCK) \
332 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
333 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
334 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
335 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
336 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
342 /* Old versions of POSIX threads on Solaris did not have recursive locks.
343 We have to implement them ourselves. */
347 pthread_mutex_t mutex;
352 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
353 STORAGECLASS gl_recursive_lock_t NAME;
354 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
355 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
356 # define gl_recursive_lock_initializer \
357 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
358 # define glthread_recursive_lock_init(LOCK) \
359 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
360 # define glthread_recursive_lock_lock(LOCK) \
361 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
362 # define glthread_recursive_lock_unlock(LOCK) \
363 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
364 # define glthread_recursive_lock_destroy(LOCK) \
365 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
366 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
367 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
368 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
369 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
373 /* -------------------------- gl_once_t datatype -------------------------- */
375 typedef pthread_once_t gl_once_t;
376 # define gl_once_define(STORAGECLASS, NAME) \
377 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
378 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
380 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \
381 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
382 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
390 /* ========================================================================= */
394 /* Use the GNU Pth threads library. */
402 # if USE_PTH_THREADS_WEAK
404 /* Use weak references to the GNU Pth threads library. */
406 # pragma weak pth_mutex_init
407 # pragma weak pth_mutex_acquire
408 # pragma weak pth_mutex_release
409 # pragma weak pth_rwlock_init
410 # pragma weak pth_rwlock_acquire
411 # pragma weak pth_rwlock_release
412 # pragma weak pth_once
414 # pragma weak pth_cancel
415 # define pth_in_use() (pth_cancel != NULL)
419 # define pth_in_use() 1
423 /* -------------------------- gl_lock_t datatype -------------------------- */
425 typedef pth_mutex_t gl_lock_t;
426 # define gl_lock_define(STORAGECLASS, NAME) \
427 STORAGECLASS pth_mutex_t NAME;
428 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
429 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
430 # define gl_lock_initializer \
432 # define glthread_lock_init(LOCK) \
433 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
434 # define glthread_lock_lock(LOCK) \
435 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
436 # define glthread_lock_unlock(LOCK) \
437 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
438 # define glthread_lock_destroy(LOCK) \
441 /* ------------------------- gl_rwlock_t datatype ------------------------- */
443 /* Pth pth_rwlock_acquire always prefers readers. No autoconf test so far. */
444 # if HAVE_PTH_RWLOCK_ACQUIRE_PREFER_WRITER
446 typedef pth_rwlock_t gl_rwlock_t;
447 # define gl_rwlock_define(STORAGECLASS, NAME) \
448 STORAGECLASS pth_rwlock_t NAME;
449 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
450 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
451 # define gl_rwlock_initializer \
453 # define glthread_rwlock_init(LOCK) \
454 (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0)
455 # define glthread_rwlock_rdlock(LOCK) \
456 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0)
457 # define glthread_rwlock_wrlock(LOCK) \
458 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0)
459 # define glthread_rwlock_unlock(LOCK) \
460 (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0)
461 # define glthread_rwlock_destroy(LOCK) \
469 pth_mutex_t lock; /* protects the remaining fields */
470 pth_cond_t waiting_readers; /* waiting readers */
471 pth_cond_t waiting_writers; /* waiting writers */
472 unsigned int waiting_writers_count; /* number of waiting writers */
473 int runcount; /* number of readers running, or -1 when a writer runs */
476 # define gl_rwlock_define(STORAGECLASS, NAME) \
477 STORAGECLASS gl_rwlock_t NAME;
478 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
479 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
480 # define gl_rwlock_initializer \
482 # define glthread_rwlock_init(LOCK) \
483 (pth_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
484 # define glthread_rwlock_rdlock(LOCK) \
485 (pth_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
486 # define glthread_rwlock_wrlock(LOCK) \
487 (pth_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
488 # define glthread_rwlock_unlock(LOCK) \
489 (pth_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
490 # define glthread_rwlock_destroy(LOCK) \
491 (pth_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
492 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
493 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
494 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
495 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
496 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
500 /* --------------------- gl_recursive_lock_t datatype --------------------- */
502 /* In Pth, mutexes are recursive by default. */
503 typedef pth_mutex_t gl_recursive_lock_t;
504 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
505 STORAGECLASS pth_mutex_t NAME;
506 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
507 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
508 # define gl_recursive_lock_initializer \
510 # define glthread_recursive_lock_init(LOCK) \
511 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
512 # define glthread_recursive_lock_lock(LOCK) \
513 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
514 # define glthread_recursive_lock_unlock(LOCK) \
515 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
516 # define glthread_recursive_lock_destroy(LOCK) \
519 /* -------------------------- gl_once_t datatype -------------------------- */
521 typedef pth_once_t gl_once_t;
522 # define gl_once_define(STORAGECLASS, NAME) \
523 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
524 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
526 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
527 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
528 extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void));
529 extern int glthread_once_singlethreaded (pth_once_t *once_control);
537 /* ========================================================================= */
539 #if USE_SOLARIS_THREADS
541 /* Use the old Solaris threads library. */
550 # if USE_SOLARIS_THREADS_WEAK
552 /* Use weak references to the old Solaris threads library. */
554 # pragma weak mutex_init
555 # pragma weak mutex_lock
556 # pragma weak mutex_unlock
557 # pragma weak mutex_destroy
558 # pragma weak rwlock_init
559 # pragma weak rw_rdlock
560 # pragma weak rw_wrlock
561 # pragma weak rw_unlock
562 # pragma weak rwlock_destroy
563 # pragma weak thr_self
565 # pragma weak thr_suspend
566 # define thread_in_use() (thr_suspend != NULL)
570 # define thread_in_use() 1
574 /* -------------------------- gl_lock_t datatype -------------------------- */
576 typedef mutex_t gl_lock_t;
577 # define gl_lock_define(STORAGECLASS, NAME) \
578 STORAGECLASS mutex_t NAME;
579 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
580 STORAGECLASS mutex_t NAME = gl_lock_initializer;
581 # define gl_lock_initializer \
583 # define glthread_lock_init(LOCK) \
584 (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
585 # define glthread_lock_lock(LOCK) \
586 (thread_in_use () ? mutex_lock (LOCK) : 0)
587 # define glthread_lock_unlock(LOCK) \
588 (thread_in_use () ? mutex_unlock (LOCK) : 0)
589 # define glthread_lock_destroy(LOCK) \
590 (thread_in_use () ? mutex_destroy (LOCK) : 0)
592 /* ------------------------- gl_rwlock_t datatype ------------------------- */
594 typedef rwlock_t gl_rwlock_t;
595 # define gl_rwlock_define(STORAGECLASS, NAME) \
596 STORAGECLASS rwlock_t NAME;
597 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
598 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
599 # define gl_rwlock_initializer \
601 # define glthread_rwlock_init(LOCK) \
602 (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
603 # define glthread_rwlock_rdlock(LOCK) \
604 (thread_in_use () ? rw_rdlock (LOCK) : 0)
605 # define glthread_rwlock_wrlock(LOCK) \
606 (thread_in_use () ? rw_wrlock (LOCK) : 0)
607 # define glthread_rwlock_unlock(LOCK) \
608 (thread_in_use () ? rw_unlock (LOCK) : 0)
609 # define glthread_rwlock_destroy(LOCK) \
610 (thread_in_use () ? rwlock_destroy (LOCK) : 0)
612 /* --------------------- gl_recursive_lock_t datatype --------------------- */
614 /* Old Solaris threads did not have recursive locks.
615 We have to implement them ourselves. */
624 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
625 STORAGECLASS gl_recursive_lock_t NAME;
626 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
627 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
628 # define gl_recursive_lock_initializer \
629 { DEFAULTMUTEX, (thread_t) 0, 0 }
630 # define glthread_recursive_lock_init(LOCK) \
631 (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
632 # define glthread_recursive_lock_lock(LOCK) \
633 (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
634 # define glthread_recursive_lock_unlock(LOCK) \
635 (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
636 # define glthread_recursive_lock_destroy(LOCK) \
637 (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
638 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
639 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
640 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
641 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
643 /* -------------------------- gl_once_t datatype -------------------------- */
651 # define gl_once_define(STORAGECLASS, NAME) \
652 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
653 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
655 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
656 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
657 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
658 extern int glthread_once_singlethreaded (gl_once_t *once_control);
666 /* ========================================================================= */
668 #if USE_WINDOWS_THREADS
670 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
671 # include <windows.h>
677 /* We can use CRITICAL_SECTION directly, rather than the native Windows Event,
678 Mutex, Semaphore types, because
679 - we need only to synchronize inside a single process (address space),
680 not inter-process locking,
681 - we don't need to support trylock operations. (TryEnterCriticalSection
682 does not work on Windows 95/98/ME. Packages that need trylock usually
683 define their own mutex type.) */
685 /* There is no way to statically initialize a CRITICAL_SECTION. It needs
686 to be done lazily, once only. For this we need spinlocks. */
688 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
690 /* -------------------------- gl_lock_t datatype -------------------------- */
694 gl_spinlock_t guard; /* protects the initialization */
695 CRITICAL_SECTION lock;
698 # define gl_lock_define(STORAGECLASS, NAME) \
699 STORAGECLASS gl_lock_t NAME;
700 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
701 STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
702 # define gl_lock_initializer \
704 # define glthread_lock_init(LOCK) \
705 (glthread_lock_init_func (LOCK), 0)
706 # define glthread_lock_lock(LOCK) \
707 glthread_lock_lock_func (LOCK)
708 # define glthread_lock_unlock(LOCK) \
709 glthread_lock_unlock_func (LOCK)
710 # define glthread_lock_destroy(LOCK) \
711 glthread_lock_destroy_func (LOCK)
712 extern void glthread_lock_init_func (gl_lock_t *lock);
713 extern int glthread_lock_lock_func (gl_lock_t *lock);
714 extern int glthread_lock_unlock_func (gl_lock_t *lock);
715 extern int glthread_lock_destroy_func (gl_lock_t *lock);
717 /* ------------------------- gl_rwlock_t datatype ------------------------- */
719 /* It is impossible to implement read-write locks using plain locks, without
720 introducing an extra thread dedicated to managing read-write locks.
721 Therefore here we need to use the low-level Event type. */
725 HANDLE *array; /* array of waiting threads, each represented by an event */
726 unsigned int count; /* number of waiting threads */
727 unsigned int alloc; /* length of allocated array */
728 unsigned int offset; /* index of first waiting thread in array */
730 gl_carray_waitqueue_t;
733 gl_spinlock_t guard; /* protects the initialization */
734 CRITICAL_SECTION lock; /* protects the remaining fields */
735 gl_carray_waitqueue_t waiting_readers; /* waiting readers */
736 gl_carray_waitqueue_t waiting_writers; /* waiting writers */
737 int runcount; /* number of readers running, or -1 when a writer runs */
740 # define gl_rwlock_define(STORAGECLASS, NAME) \
741 STORAGECLASS gl_rwlock_t NAME;
742 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
743 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
744 # define gl_rwlock_initializer \
746 # define glthread_rwlock_init(LOCK) \
747 (glthread_rwlock_init_func (LOCK), 0)
748 # define glthread_rwlock_rdlock(LOCK) \
749 glthread_rwlock_rdlock_func (LOCK)
750 # define glthread_rwlock_wrlock(LOCK) \
751 glthread_rwlock_wrlock_func (LOCK)
752 # define glthread_rwlock_unlock(LOCK) \
753 glthread_rwlock_unlock_func (LOCK)
754 # define glthread_rwlock_destroy(LOCK) \
755 glthread_rwlock_destroy_func (LOCK)
756 extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
757 extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock);
758 extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock);
759 extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock);
760 extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock);
762 /* --------------------- gl_recursive_lock_t datatype --------------------- */
764 /* The native Windows documentation says that CRITICAL_SECTION already
765 implements a recursive lock. But we need not rely on it: It's easy to
766 implement a recursive lock without this assumption. */
770 gl_spinlock_t guard; /* protects the initialization */
773 CRITICAL_SECTION lock;
776 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
777 STORAGECLASS gl_recursive_lock_t NAME;
778 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
779 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
780 # define gl_recursive_lock_initializer \
782 # define glthread_recursive_lock_init(LOCK) \
783 (glthread_recursive_lock_init_func (LOCK), 0)
784 # define glthread_recursive_lock_lock(LOCK) \
785 glthread_recursive_lock_lock_func (LOCK)
786 # define glthread_recursive_lock_unlock(LOCK) \
787 glthread_recursive_lock_unlock_func (LOCK)
788 # define glthread_recursive_lock_destroy(LOCK) \
789 glthread_recursive_lock_destroy_func (LOCK)
790 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
791 extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock);
792 extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock);
793 extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock);
795 /* -------------------------- gl_once_t datatype -------------------------- */
800 volatile long started;
801 CRITICAL_SECTION lock;
804 # define gl_once_define(STORAGECLASS, NAME) \
805 STORAGECLASS gl_once_t NAME = { -1, -1 };
806 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
807 (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
808 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
816 /* ========================================================================= */
818 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
820 /* Provide dummy implementation if threads are not supported. */
822 /* -------------------------- gl_lock_t datatype -------------------------- */
824 typedef int gl_lock_t;
825 # define gl_lock_define(STORAGECLASS, NAME)
826 # define gl_lock_define_initialized(STORAGECLASS, NAME)
827 # define glthread_lock_init(NAME) 0
828 # define glthread_lock_lock(NAME) 0
829 # define glthread_lock_unlock(NAME) 0
830 # define glthread_lock_destroy(NAME) 0
832 /* ------------------------- gl_rwlock_t datatype ------------------------- */
834 typedef int gl_rwlock_t;
835 # define gl_rwlock_define(STORAGECLASS, NAME)
836 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
837 # define glthread_rwlock_init(NAME) 0
838 # define glthread_rwlock_rdlock(NAME) 0
839 # define glthread_rwlock_wrlock(NAME) 0
840 # define glthread_rwlock_unlock(NAME) 0
841 # define glthread_rwlock_destroy(NAME) 0
843 /* --------------------- gl_recursive_lock_t datatype --------------------- */
845 typedef int gl_recursive_lock_t;
846 # define gl_recursive_lock_define(STORAGECLASS, NAME)
847 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
848 # define glthread_recursive_lock_init(NAME) 0
849 # define glthread_recursive_lock_lock(NAME) 0
850 # define glthread_recursive_lock_unlock(NAME) 0
851 # define glthread_recursive_lock_destroy(NAME) 0
853 /* -------------------------- gl_once_t datatype -------------------------- */
855 typedef int gl_once_t;
856 # define gl_once_define(STORAGECLASS, NAME) \
857 STORAGECLASS gl_once_t NAME = 0;
858 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
859 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
863 /* ========================================================================= */
865 /* Macros with built-in error handling. */
867 /* -------------------------- gl_lock_t datatype -------------------------- */
869 #define gl_lock_init(NAME) \
872 if (glthread_lock_init (&NAME)) \
876 #define gl_lock_lock(NAME) \
879 if (glthread_lock_lock (&NAME)) \
883 #define gl_lock_unlock(NAME) \
886 if (glthread_lock_unlock (&NAME)) \
890 #define gl_lock_destroy(NAME) \
893 if (glthread_lock_destroy (&NAME)) \
898 /* ------------------------- gl_rwlock_t datatype ------------------------- */
900 #define gl_rwlock_init(NAME) \
903 if (glthread_rwlock_init (&NAME)) \
907 #define gl_rwlock_rdlock(NAME) \
910 if (glthread_rwlock_rdlock (&NAME)) \
914 #define gl_rwlock_wrlock(NAME) \
917 if (glthread_rwlock_wrlock (&NAME)) \
921 #define gl_rwlock_unlock(NAME) \
924 if (glthread_rwlock_unlock (&NAME)) \
928 #define gl_rwlock_destroy(NAME) \
931 if (glthread_rwlock_destroy (&NAME)) \
936 /* --------------------- gl_recursive_lock_t datatype --------------------- */
938 #define gl_recursive_lock_init(NAME) \
941 if (glthread_recursive_lock_init (&NAME)) \
945 #define gl_recursive_lock_lock(NAME) \
948 if (glthread_recursive_lock_lock (&NAME)) \
952 #define gl_recursive_lock_unlock(NAME) \
955 if (glthread_recursive_lock_unlock (&NAME)) \
959 #define gl_recursive_lock_destroy(NAME) \
962 if (glthread_recursive_lock_destroy (&NAME)) \
967 /* -------------------------- gl_once_t datatype -------------------------- */
969 #define gl_once(NAME, INITFUNCTION) \
972 if (glthread_once (&NAME, INITFUNCTION)) \
977 /* ========================================================================= */