1 /* Locking in multithreaded situations.
2 Copyright (C) 2005-2008 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published
6 by the Free Software Foundation; either version 2, 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 GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 /* Written by Bruno Haible <bruno@clisp.org>, 2005.
20 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
23 /* This file contains locking primitives for use with a given thread library.
24 It does not contain primitives for creating threads or for other
25 synchronization primitives.
27 Normal (non-recursive) locks:
29 Declaration: gl_lock_define(extern, name)
30 Initializer: gl_lock_define_initialized(, name)
31 Initialization: gl_lock_init (name);
32 Taking the lock: gl_lock_lock (name);
33 Releasing the lock: gl_lock_unlock (name);
34 De-initialization: gl_lock_destroy (name);
35 Equivalent functions with control of error handling:
36 Initialization: err = glthread_lock_init (&name);
37 Taking the lock: err = glthread_lock_lock (&name);
38 Releasing the lock: err = glthread_lock_unlock (&name);
39 De-initialization: err = glthread_lock_destroy (&name);
41 Read-Write (non-recursive) locks:
43 Declaration: gl_rwlock_define(extern, name)
44 Initializer: gl_rwlock_define_initialized(, name)
45 Initialization: gl_rwlock_init (name);
46 Taking the lock: gl_rwlock_rdlock (name);
47 gl_rwlock_wrlock (name);
48 Releasing the lock: gl_rwlock_unlock (name);
49 De-initialization: gl_rwlock_destroy (name);
50 Equivalent functions with control of error handling:
51 Initialization: err = glthread_rwlock_init (&name);
52 Taking the lock: err = glthread_rwlock_rdlock (&name);
53 err = glthread_rwlock_wrlock (&name);
54 Releasing the lock: err = glthread_rwlock_unlock (&name);
55 De-initialization: err = glthread_rwlock_destroy (&name);
58 Type: gl_recursive_lock_t
59 Declaration: gl_recursive_lock_define(extern, name)
60 Initializer: gl_recursive_lock_define_initialized(, name)
61 Initialization: gl_recursive_lock_init (name);
62 Taking the lock: gl_recursive_lock_lock (name);
63 Releasing the lock: gl_recursive_lock_unlock (name);
64 De-initialization: gl_recursive_lock_destroy (name);
65 Equivalent functions with control of error handling:
66 Initialization: err = glthread_recursive_lock_init (&name);
67 Taking the lock: err = glthread_recursive_lock_lock (&name);
68 Releasing the lock: err = glthread_recursive_lock_unlock (&name);
69 De-initialization: err = glthread_recursive_lock_destroy (&name);
73 Initializer: gl_once_define(extern, name)
74 Execution: gl_once (name, initfunction);
75 Equivalent functions with control of error handling:
76 Execution: err = glthread_once (&name, initfunction);
86 /* ========================================================================= */
90 /* Use the POSIX threads library. */
98 # if PTHREAD_IN_USE_DETECTION_HARD
100 /* The pthread_in_use() detection needs to be done at runtime. */
101 # define pthread_in_use() \
103 extern int glthread_in_use (void);
107 # if USE_POSIX_THREADS_WEAK
109 /* Use weak references to the POSIX threads library. */
111 /* Weak references avoid dragging in external libraries if the other parts
112 of the program don't use them. Here we use them, because we don't want
113 every program that uses libintl to depend on libpthread. This assumes
114 that libpthread would not be loaded after libintl; i.e. if libintl is
115 loaded first, by an executable that does not depend on libpthread, and
116 then a module is dynamically loaded that depends on libpthread, libintl
117 will not be multithread-safe. */
119 /* The way to test at runtime whether libpthread is present is to test
120 whether a function pointer's value, such as &pthread_mutex_init, is
121 non-NULL. However, some versions of GCC have a bug through which, in
122 PIC mode, &foo != NULL always evaluates to true if there is a direct
123 call to foo(...) in the same function. To avoid this, we test the
124 address of a function in libpthread that we don't use. */
126 # pragma weak pthread_mutex_init
127 # pragma weak pthread_mutex_lock
128 # pragma weak pthread_mutex_unlock
129 # pragma weak pthread_mutex_destroy
130 # pragma weak pthread_rwlock_init
131 # pragma weak pthread_rwlock_rdlock
132 # pragma weak pthread_rwlock_wrlock
133 # pragma weak pthread_rwlock_unlock
134 # pragma weak pthread_rwlock_destroy
135 # pragma weak pthread_once
136 # pragma weak pthread_cond_init
137 # pragma weak pthread_cond_wait
138 # pragma weak pthread_cond_signal
139 # pragma weak pthread_cond_broadcast
140 # pragma weak pthread_cond_destroy
141 # pragma weak pthread_mutexattr_init
142 # pragma weak pthread_mutexattr_settype
143 # pragma weak pthread_mutexattr_destroy
144 # ifndef pthread_self
145 # pragma weak pthread_self
148 # if !PTHREAD_IN_USE_DETECTION_HARD
149 # pragma weak pthread_cancel
150 # define pthread_in_use() (pthread_cancel != NULL)
155 # if !PTHREAD_IN_USE_DETECTION_HARD
156 # define pthread_in_use() 1
161 /* -------------------------- gl_lock_t datatype -------------------------- */
163 typedef pthread_mutex_t gl_lock_t;
164 # define gl_lock_define(STORAGECLASS, NAME) \
165 STORAGECLASS pthread_mutex_t NAME;
166 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
167 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
168 # define gl_lock_initializer \
169 PTHREAD_MUTEX_INITIALIZER
170 # define glthread_lock_init(LOCK) \
171 (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
172 # define glthread_lock_lock(LOCK) \
173 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
174 # define glthread_lock_unlock(LOCK) \
175 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
176 # define glthread_lock_destroy(LOCK) \
177 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
179 /* ------------------------- gl_rwlock_t datatype ------------------------- */
181 # if HAVE_PTHREAD_RWLOCK
183 # ifdef PTHREAD_RWLOCK_INITIALIZER
185 typedef pthread_rwlock_t gl_rwlock_t;
186 # define gl_rwlock_define(STORAGECLASS, NAME) \
187 STORAGECLASS pthread_rwlock_t NAME;
188 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
189 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
190 # define gl_rwlock_initializer \
191 PTHREAD_RWLOCK_INITIALIZER
192 # define glthread_rwlock_init(LOCK) \
193 (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
194 # define glthread_rwlock_rdlock(LOCK) \
195 (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
196 # define glthread_rwlock_wrlock(LOCK) \
197 (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
198 # define glthread_rwlock_unlock(LOCK) \
199 (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
200 # define glthread_rwlock_destroy(LOCK) \
201 (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
208 pthread_mutex_t guard; /* protects the initialization */
209 pthread_rwlock_t rwlock; /* read-write lock */
212 # define gl_rwlock_define(STORAGECLASS, NAME) \
213 STORAGECLASS gl_rwlock_t NAME;
214 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
215 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
216 # define gl_rwlock_initializer \
217 { 0, PTHREAD_MUTEX_INITIALIZER }
218 # define glthread_rwlock_init(LOCK) \
219 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
220 # define glthread_rwlock_rdlock(LOCK) \
221 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
222 # define glthread_rwlock_wrlock(LOCK) \
223 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
224 # define glthread_rwlock_unlock(LOCK) \
225 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
226 # define glthread_rwlock_destroy(LOCK) \
227 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
228 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
229 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
230 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
231 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
232 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
240 pthread_mutex_t lock; /* protects the remaining fields */
241 pthread_cond_t waiting_readers; /* waiting readers */
242 pthread_cond_t waiting_writers; /* waiting writers */
243 unsigned int waiting_writers_count; /* number of waiting writers */
244 int runcount; /* number of readers running, or -1 when a writer runs */
247 # define gl_rwlock_define(STORAGECLASS, NAME) \
248 STORAGECLASS gl_rwlock_t NAME;
249 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
250 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
251 # define gl_rwlock_initializer \
252 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
253 # define glthread_rwlock_init(LOCK) \
254 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
255 # define glthread_rwlock_rdlock(LOCK) \
256 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
257 # define glthread_rwlock_wrlock(LOCK) \
258 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
259 # define glthread_rwlock_unlock(LOCK) \
260 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
261 # define glthread_rwlock_destroy(LOCK) \
262 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
263 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
264 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
265 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
266 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
267 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
271 /* --------------------- gl_recursive_lock_t datatype --------------------- */
273 # if HAVE_PTHREAD_MUTEX_RECURSIVE
275 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
277 typedef pthread_mutex_t gl_recursive_lock_t;
278 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
279 STORAGECLASS pthread_mutex_t NAME;
280 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
281 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
282 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
283 # define gl_recursive_lock_initializer \
284 PTHREAD_RECURSIVE_MUTEX_INITIALIZER
286 # define gl_recursive_lock_initializer \
287 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
289 # define glthread_recursive_lock_init(LOCK) \
290 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
291 # define glthread_recursive_lock_lock(LOCK) \
292 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
293 # define glthread_recursive_lock_unlock(LOCK) \
294 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
295 # define glthread_recursive_lock_destroy(LOCK) \
296 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
297 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
303 pthread_mutex_t recmutex; /* recursive mutex */
304 pthread_mutex_t guard; /* protects the initialization */
308 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
309 STORAGECLASS gl_recursive_lock_t NAME;
310 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
311 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
312 # define gl_recursive_lock_initializer \
313 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
314 # define glthread_recursive_lock_init(LOCK) \
315 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
316 # define glthread_recursive_lock_lock(LOCK) \
317 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
318 # define glthread_recursive_lock_unlock(LOCK) \
319 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
320 # define glthread_recursive_lock_destroy(LOCK) \
321 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
322 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
323 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
324 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
325 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
331 /* Old versions of POSIX threads on Solaris did not have recursive locks.
332 We have to implement them ourselves. */
336 pthread_mutex_t mutex;
341 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
342 STORAGECLASS gl_recursive_lock_t NAME;
343 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
344 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
345 # define gl_recursive_lock_initializer \
346 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
347 # define glthread_recursive_lock_init(LOCK) \
348 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
349 # define glthread_recursive_lock_lock(LOCK) \
350 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
351 # define glthread_recursive_lock_unlock(LOCK) \
352 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
353 # define glthread_recursive_lock_destroy(LOCK) \
354 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
355 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
356 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
357 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
358 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
362 /* -------------------------- gl_once_t datatype -------------------------- */
364 typedef pthread_once_t gl_once_t;
365 # define gl_once_define(STORAGECLASS, NAME) \
366 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
367 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
369 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \
370 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
371 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
379 /* ========================================================================= */
383 /* Use the GNU Pth threads library. */
391 # if USE_PTH_THREADS_WEAK
393 /* Use weak references to the GNU Pth threads library. */
395 # pragma weak pth_mutex_init
396 # pragma weak pth_mutex_acquire
397 # pragma weak pth_mutex_release
398 # pragma weak pth_rwlock_init
399 # pragma weak pth_rwlock_acquire
400 # pragma weak pth_rwlock_release
401 # pragma weak pth_once
403 # pragma weak pth_cancel
404 # define pth_in_use() (pth_cancel != NULL)
408 # define pth_in_use() 1
412 /* -------------------------- gl_lock_t datatype -------------------------- */
414 typedef pth_mutex_t gl_lock_t;
415 # define gl_lock_define(STORAGECLASS, NAME) \
416 STORAGECLASS pth_mutex_t NAME;
417 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
418 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
419 # define gl_lock_initializer \
421 # define glthread_lock_init(LOCK) \
422 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
423 # define glthread_lock_lock(LOCK) \
424 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
425 # define glthread_lock_unlock(LOCK) \
426 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
427 # define glthread_lock_destroy(LOCK) \
430 /* ------------------------- gl_rwlock_t datatype ------------------------- */
432 typedef pth_rwlock_t gl_rwlock_t;
433 # define gl_rwlock_define(STORAGECLASS, NAME) \
434 STORAGECLASS pth_rwlock_t NAME;
435 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
436 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
437 # define gl_rwlock_initializer \
439 # define glthread_rwlock_init(LOCK) \
440 (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0)
441 # define glthread_rwlock_rdlock(LOCK) \
442 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0)
443 # define glthread_rwlock_wrlock(LOCK) \
444 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0)
445 # define glthread_rwlock_unlock(LOCK) \
446 (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0)
447 # define glthread_rwlock_destroy(LOCK) \
450 /* --------------------- gl_recursive_lock_t datatype --------------------- */
452 /* In Pth, mutexes are recursive by default. */
453 typedef pth_mutex_t gl_recursive_lock_t;
454 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
455 STORAGECLASS pth_mutex_t NAME;
456 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
457 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
458 # define gl_recursive_lock_initializer \
460 # define glthread_recursive_lock_init(LOCK) \
461 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
462 # define glthread_recursive_lock_lock(LOCK) \
463 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
464 # define glthread_recursive_lock_unlock(LOCK) \
465 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
466 # define glthread_recursive_lock_destroy(LOCK) \
469 /* -------------------------- gl_once_t datatype -------------------------- */
471 typedef pth_once_t gl_once_t;
472 # define gl_once_define(STORAGECLASS, NAME) \
473 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
474 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
476 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
477 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
478 extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void));
479 extern int glthread_once_singlethreaded (pth_once_t *once_control);
487 /* ========================================================================= */
489 #if USE_SOLARIS_THREADS
491 /* Use the old Solaris threads library. */
500 # if USE_SOLARIS_THREADS_WEAK
502 /* Use weak references to the old Solaris threads library. */
504 # pragma weak mutex_init
505 # pragma weak mutex_lock
506 # pragma weak mutex_unlock
507 # pragma weak mutex_destroy
508 # pragma weak rwlock_init
509 # pragma weak rw_rdlock
510 # pragma weak rw_wrlock
511 # pragma weak rw_unlock
512 # pragma weak rwlock_destroy
513 # pragma weak thr_self
515 # pragma weak thr_suspend
516 # define thread_in_use() (thr_suspend != NULL)
520 # define thread_in_use() 1
524 /* -------------------------- gl_lock_t datatype -------------------------- */
526 typedef mutex_t gl_lock_t;
527 # define gl_lock_define(STORAGECLASS, NAME) \
528 STORAGECLASS mutex_t NAME;
529 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
530 STORAGECLASS mutex_t NAME = gl_lock_initializer;
531 # define gl_lock_initializer \
533 # define glthread_lock_init(LOCK) \
534 (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
535 # define glthread_lock_lock(LOCK) \
536 (thread_in_use () ? mutex_lock (LOCK) : 0)
537 # define glthread_lock_unlock(LOCK) \
538 (thread_in_use () ? mutex_unlock (LOCK) : 0)
539 # define glthread_lock_destroy(LOCK) \
540 (thread_in_use () ? mutex_destroy (LOCK) : 0)
542 /* ------------------------- gl_rwlock_t datatype ------------------------- */
544 typedef rwlock_t gl_rwlock_t;
545 # define gl_rwlock_define(STORAGECLASS, NAME) \
546 STORAGECLASS rwlock_t NAME;
547 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
548 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
549 # define gl_rwlock_initializer \
551 # define glthread_rwlock_init(LOCK) \
552 (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
553 # define glthread_rwlock_rdlock(LOCK) \
554 (thread_in_use () ? rw_rdlock (LOCK) : 0)
555 # define glthread_rwlock_wrlock(LOCK) \
556 (thread_in_use () ? rw_wrlock (LOCK) : 0)
557 # define glthread_rwlock_unlock(LOCK) \
558 (thread_in_use () ? rw_unlock (LOCK) : 0)
559 # define glthread_rwlock_destroy(LOCK) \
560 (thread_in_use () ? rwlock_destroy (LOCK) : 0)
562 /* --------------------- gl_recursive_lock_t datatype --------------------- */
564 /* Old Solaris threads did not have recursive locks.
565 We have to implement them ourselves. */
574 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
575 STORAGECLASS gl_recursive_lock_t NAME;
576 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
577 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
578 # define gl_recursive_lock_initializer \
579 { DEFAULTMUTEX, (thread_t) 0, 0 }
580 # define glthread_recursive_lock_init(LOCK) \
581 (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
582 # define glthread_recursive_lock_lock(LOCK) \
583 (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
584 # define glthread_recursive_lock_unlock(LOCK) \
585 (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
586 # define glthread_recursive_lock_destroy(LOCK) \
587 (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
588 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
589 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
590 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
591 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
593 /* -------------------------- gl_once_t datatype -------------------------- */
601 # define gl_once_define(STORAGECLASS, NAME) \
602 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
603 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
605 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
606 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
607 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
608 extern int glthread_once_singlethreaded (gl_once_t *once_control);
616 /* ========================================================================= */
618 #if USE_WIN32_THREADS
620 # include <windows.h>
626 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
627 Semaphore types, because
628 - we need only to synchronize inside a single process (address space),
629 not inter-process locking,
630 - we don't need to support trylock operations. (TryEnterCriticalSection
631 does not work on Windows 95/98/ME. Packages that need trylock usually
632 define their own mutex type.) */
634 /* There is no way to statically initialize a CRITICAL_SECTION. It needs
635 to be done lazily, once only. For this we need spinlocks. */
637 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
639 /* -------------------------- gl_lock_t datatype -------------------------- */
643 gl_spinlock_t guard; /* protects the initialization */
644 CRITICAL_SECTION lock;
647 # define gl_lock_define(STORAGECLASS, NAME) \
648 STORAGECLASS gl_lock_t NAME;
649 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
650 STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
651 # define gl_lock_initializer \
653 # define glthread_lock_init(LOCK) \
654 (glthread_lock_init_func (LOCK), 0)
655 # define glthread_lock_lock(LOCK) \
656 glthread_lock_lock_func (LOCK)
657 # define glthread_lock_unlock(LOCK) \
658 glthread_lock_unlock_func (LOCK)
659 # define glthread_lock_destroy(LOCK) \
660 glthread_lock_destroy_func (LOCK)
661 extern void glthread_lock_init_func (gl_lock_t *lock);
662 extern int glthread_lock_lock_func (gl_lock_t *lock);
663 extern int glthread_lock_unlock_func (gl_lock_t *lock);
664 extern int glthread_lock_destroy_func (gl_lock_t *lock);
666 /* ------------------------- gl_rwlock_t datatype ------------------------- */
668 /* It is impossible to implement read-write locks using plain locks, without
669 introducing an extra thread dedicated to managing read-write locks.
670 Therefore here we need to use the low-level Event type. */
674 HANDLE *array; /* array of waiting threads, each represented by an event */
675 unsigned int count; /* number of waiting threads */
676 unsigned int alloc; /* length of allocated array */
677 unsigned int offset; /* index of first waiting thread in array */
679 gl_carray_waitqueue_t;
682 gl_spinlock_t guard; /* protects the initialization */
683 CRITICAL_SECTION lock; /* protects the remaining fields */
684 gl_carray_waitqueue_t waiting_readers; /* waiting readers */
685 gl_carray_waitqueue_t waiting_writers; /* waiting writers */
686 int runcount; /* number of readers running, or -1 when a writer runs */
689 # define gl_rwlock_define(STORAGECLASS, NAME) \
690 STORAGECLASS gl_rwlock_t NAME;
691 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
692 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
693 # define gl_rwlock_initializer \
695 # define glthread_rwlock_init(LOCK) \
696 (glthread_rwlock_init_func (LOCK), 0)
697 # define glthread_rwlock_rdlock(LOCK) \
698 glthread_rwlock_rdlock_func (LOCK)
699 # define glthread_rwlock_wrlock(LOCK) \
700 glthread_rwlock_wrlock_func (LOCK)
701 # define glthread_rwlock_unlock(LOCK) \
702 glthread_rwlock_unlock_func (LOCK)
703 # define glthread_rwlock_destroy(LOCK) \
704 glthread_rwlock_destroy_func (LOCK)
705 extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
706 extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock);
707 extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock);
708 extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock);
709 extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock);
711 /* --------------------- gl_recursive_lock_t datatype --------------------- */
713 /* The Win32 documentation says that CRITICAL_SECTION already implements a
714 recursive lock. But we need not rely on it: It's easy to implement a
715 recursive lock without this assumption. */
719 gl_spinlock_t guard; /* protects the initialization */
722 CRITICAL_SECTION lock;
725 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
726 STORAGECLASS gl_recursive_lock_t NAME;
727 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
728 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
729 # define gl_recursive_lock_initializer \
731 # define glthread_recursive_lock_init(LOCK) \
732 (glthread_recursive_lock_init_func (LOCK), 0)
733 # define glthread_recursive_lock_lock(LOCK) \
734 glthread_recursive_lock_lock_func (LOCK)
735 # define glthread_recursive_lock_unlock(LOCK) \
736 glthread_recursive_lock_unlock_func (LOCK)
737 # define glthread_recursive_lock_destroy(LOCK) \
738 glthread_recursive_lock_destroy_func (LOCK)
739 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
740 extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock);
741 extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock);
742 extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock);
744 /* -------------------------- gl_once_t datatype -------------------------- */
749 volatile long started;
750 CRITICAL_SECTION lock;
753 # define gl_once_define(STORAGECLASS, NAME) \
754 STORAGECLASS gl_once_t NAME = { -1, -1 };
755 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
756 (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
757 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
765 /* ========================================================================= */
767 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
769 /* Provide dummy implementation if threads are not supported. */
771 /* -------------------------- gl_lock_t datatype -------------------------- */
773 typedef int gl_lock_t;
774 # define gl_lock_define(STORAGECLASS, NAME)
775 # define gl_lock_define_initialized(STORAGECLASS, NAME)
776 # define glthread_lock_init(NAME) 0
777 # define glthread_lock_lock(NAME) 0
778 # define glthread_lock_unlock(NAME) 0
779 # define glthread_lock_destroy(NAME) 0
781 /* ------------------------- gl_rwlock_t datatype ------------------------- */
783 typedef int gl_rwlock_t;
784 # define gl_rwlock_define(STORAGECLASS, NAME)
785 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
786 # define glthread_rwlock_init(NAME) 0
787 # define glthread_rwlock_rdlock(NAME) 0
788 # define glthread_rwlock_wrlock(NAME) 0
789 # define glthread_rwlock_unlock(NAME) 0
790 # define glthread_rwlock_destroy(NAME) 0
792 /* --------------------- gl_recursive_lock_t datatype --------------------- */
794 typedef int gl_recursive_lock_t;
795 # define gl_recursive_lock_define(STORAGECLASS, NAME)
796 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
797 # define glthread_recursive_lock_init(NAME) 0
798 # define glthread_recursive_lock_lock(NAME) 0
799 # define glthread_recursive_lock_unlock(NAME) 0
800 # define glthread_recursive_lock_destroy(NAME) 0
802 /* -------------------------- gl_once_t datatype -------------------------- */
804 typedef int gl_once_t;
805 # define gl_once_define(STORAGECLASS, NAME) \
806 STORAGECLASS gl_once_t NAME = 0;
807 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
808 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
812 /* ========================================================================= */
814 /* Macros with built-in error handling. */
816 /* -------------------------- gl_lock_t datatype -------------------------- */
818 #define gl_lock_init(NAME) \
821 if (glthread_lock_init (&NAME)) \
825 #define gl_lock_lock(NAME) \
828 if (glthread_lock_lock (&NAME)) \
832 #define gl_lock_unlock(NAME) \
835 if (glthread_lock_unlock (&NAME)) \
839 #define gl_lock_destroy(NAME) \
842 if (glthread_lock_destroy (&NAME)) \
847 /* ------------------------- gl_rwlock_t datatype ------------------------- */
849 #define gl_rwlock_init(NAME) \
852 if (glthread_rwlock_init (&NAME)) \
856 #define gl_rwlock_rdlock(NAME) \
859 if (glthread_rwlock_rdlock (&NAME)) \
863 #define gl_rwlock_wrlock(NAME) \
866 if (glthread_rwlock_wrlock (&NAME)) \
870 #define gl_rwlock_unlock(NAME) \
873 if (glthread_rwlock_unlock (&NAME)) \
877 #define gl_rwlock_destroy(NAME) \
880 if (glthread_rwlock_destroy (&NAME)) \
885 /* --------------------- gl_recursive_lock_t datatype --------------------- */
887 #define gl_recursive_lock_init(NAME) \
890 if (glthread_recursive_lock_init (&NAME)) \
894 #define gl_recursive_lock_lock(NAME) \
897 if (glthread_recursive_lock_lock (&NAME)) \
901 #define gl_recursive_lock_unlock(NAME) \
904 if (glthread_recursive_lock_unlock (&NAME)) \
908 #define gl_recursive_lock_destroy(NAME) \
911 if (glthread_recursive_lock_destroy (&NAME)) \
916 /* -------------------------- gl_once_t datatype -------------------------- */
918 #define gl_once(NAME, INITFUNCTION) \
921 if (glthread_once (&NAME, INITFUNCTION)) \
926 /* ========================================================================= */