1 /* Locking in multithreaded situations.
2 Copyright (C) 2005-2010 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, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* Written by Bruno Haible <bruno@clisp.org>, 2005.
19 Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
22 /* This file contains locking primitives for use with a given thread library.
23 It does not contain primitives for creating threads or for other
24 synchronization primitives.
26 Normal (non-recursive) locks:
28 Declaration: gl_lock_define(extern, name)
29 Initializer: gl_lock_define_initialized(, name)
30 Initialization: gl_lock_init (name);
31 Taking the lock: gl_lock_lock (name);
32 Releasing the lock: gl_lock_unlock (name);
33 De-initialization: gl_lock_destroy (name);
34 Equivalent functions with control of error handling:
35 Initialization: err = glthread_lock_init (&name);
36 Taking the lock: err = glthread_lock_lock (&name);
37 Releasing the lock: err = glthread_lock_unlock (&name);
38 De-initialization: err = glthread_lock_destroy (&name);
40 Read-Write (non-recursive) locks:
42 Declaration: gl_rwlock_define(extern, name)
43 Initializer: gl_rwlock_define_initialized(, name)
44 Initialization: gl_rwlock_init (name);
45 Taking the lock: gl_rwlock_rdlock (name);
46 gl_rwlock_wrlock (name);
47 Releasing the lock: gl_rwlock_unlock (name);
48 De-initialization: gl_rwlock_destroy (name);
49 Equivalent functions with control of error handling:
50 Initialization: err = glthread_rwlock_init (&name);
51 Taking the lock: err = glthread_rwlock_rdlock (&name);
52 err = glthread_rwlock_wrlock (&name);
53 Releasing the lock: err = glthread_rwlock_unlock (&name);
54 De-initialization: err = glthread_rwlock_destroy (&name);
57 Type: gl_recursive_lock_t
58 Declaration: gl_recursive_lock_define(extern, name)
59 Initializer: gl_recursive_lock_define_initialized(, name)
60 Initialization: gl_recursive_lock_init (name);
61 Taking the lock: gl_recursive_lock_lock (name);
62 Releasing the lock: gl_recursive_lock_unlock (name);
63 De-initialization: gl_recursive_lock_destroy (name);
64 Equivalent functions with control of error handling:
65 Initialization: err = glthread_recursive_lock_init (&name);
66 Taking the lock: err = glthread_recursive_lock_lock (&name);
67 Releasing the lock: err = glthread_recursive_lock_unlock (&name);
68 De-initialization: err = glthread_recursive_lock_destroy (&name);
72 Initializer: gl_once_define(extern, name)
73 Execution: gl_once (name, initfunction);
74 Equivalent functions with control of error handling:
75 Execution: err = glthread_once (&name, initfunction);
85 /* ========================================================================= */
89 /* Use the POSIX threads library. */
97 # if PTHREAD_IN_USE_DETECTION_HARD
99 /* The pthread_in_use() detection needs to be done at runtime. */
100 # define pthread_in_use() \
102 extern int glthread_in_use (void);
106 # if USE_POSIX_THREADS_WEAK
108 /* Use weak references to the POSIX threads library. */
110 /* Weak references avoid dragging in external libraries if the other parts
111 of the program don't use them. Here we use them, because we don't want
112 every program that uses libintl to depend on libpthread. This assumes
113 that libpthread would not be loaded after libintl; i.e. if libintl is
114 loaded first, by an executable that does not depend on libpthread, and
115 then a module is dynamically loaded that depends on libpthread, libintl
116 will not be multithread-safe. */
118 /* The way to test at runtime whether libpthread is present is to test
119 whether a function pointer's value, such as &pthread_mutex_init, is
120 non-NULL. However, some versions of GCC have a bug through which, in
121 PIC mode, &foo != NULL always evaluates to true if there is a direct
122 call to foo(...) in the same function. To avoid this, we test the
123 address of a function in libpthread that we don't use. */
125 # pragma weak pthread_mutex_init
126 # pragma weak pthread_mutex_lock
127 # pragma weak pthread_mutex_unlock
128 # pragma weak pthread_mutex_destroy
129 # pragma weak pthread_rwlock_init
130 # pragma weak pthread_rwlock_rdlock
131 # pragma weak pthread_rwlock_wrlock
132 # pragma weak pthread_rwlock_unlock
133 # pragma weak pthread_rwlock_destroy
134 # pragma weak pthread_once
135 # pragma weak pthread_cond_init
136 # pragma weak pthread_cond_wait
137 # pragma weak pthread_cond_signal
138 # pragma weak pthread_cond_broadcast
139 # pragma weak pthread_cond_destroy
140 # pragma weak pthread_mutexattr_init
141 # pragma weak pthread_mutexattr_settype
142 # pragma weak pthread_mutexattr_destroy
143 # ifndef pthread_self
144 # pragma weak pthread_self
147 # if !PTHREAD_IN_USE_DETECTION_HARD
148 # pragma weak pthread_cancel
149 # define pthread_in_use() (pthread_cancel != NULL)
154 # if !PTHREAD_IN_USE_DETECTION_HARD
155 # define pthread_in_use() 1
160 /* -------------------------- gl_lock_t datatype -------------------------- */
162 typedef pthread_mutex_t gl_lock_t;
163 # define gl_lock_define(STORAGECLASS, NAME) \
164 STORAGECLASS pthread_mutex_t NAME;
165 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
166 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
167 # define gl_lock_initializer \
168 PTHREAD_MUTEX_INITIALIZER
169 # define glthread_lock_init(LOCK) \
170 (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
171 # define glthread_lock_lock(LOCK) \
172 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
173 # define glthread_lock_unlock(LOCK) \
174 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
175 # define glthread_lock_destroy(LOCK) \
176 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
178 /* ------------------------- gl_rwlock_t datatype ------------------------- */
180 # if HAVE_PTHREAD_RWLOCK
182 # ifdef PTHREAD_RWLOCK_INITIALIZER
184 typedef pthread_rwlock_t gl_rwlock_t;
185 # define gl_rwlock_define(STORAGECLASS, NAME) \
186 STORAGECLASS pthread_rwlock_t NAME;
187 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
188 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
189 # define gl_rwlock_initializer \
190 PTHREAD_RWLOCK_INITIALIZER
191 # define glthread_rwlock_init(LOCK) \
192 (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
193 # define glthread_rwlock_rdlock(LOCK) \
194 (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
195 # define glthread_rwlock_wrlock(LOCK) \
196 (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
197 # define glthread_rwlock_unlock(LOCK) \
198 (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
199 # define glthread_rwlock_destroy(LOCK) \
200 (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
207 pthread_mutex_t guard; /* protects the initialization */
208 pthread_rwlock_t rwlock; /* read-write lock */
211 # define gl_rwlock_define(STORAGECLASS, NAME) \
212 STORAGECLASS gl_rwlock_t NAME;
213 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
214 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
215 # define gl_rwlock_initializer \
216 { 0, PTHREAD_MUTEX_INITIALIZER }
217 # define glthread_rwlock_init(LOCK) \
218 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
219 # define glthread_rwlock_rdlock(LOCK) \
220 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
221 # define glthread_rwlock_wrlock(LOCK) \
222 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
223 # define glthread_rwlock_unlock(LOCK) \
224 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
225 # define glthread_rwlock_destroy(LOCK) \
226 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
227 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
228 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
229 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
230 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
231 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
239 pthread_mutex_t lock; /* protects the remaining fields */
240 pthread_cond_t waiting_readers; /* waiting readers */
241 pthread_cond_t waiting_writers; /* waiting writers */
242 unsigned int waiting_writers_count; /* number of waiting writers */
243 int runcount; /* number of readers running, or -1 when a writer runs */
246 # define gl_rwlock_define(STORAGECLASS, NAME) \
247 STORAGECLASS gl_rwlock_t NAME;
248 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
249 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
250 # define gl_rwlock_initializer \
251 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
252 # define glthread_rwlock_init(LOCK) \
253 (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
254 # define glthread_rwlock_rdlock(LOCK) \
255 (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
256 # define glthread_rwlock_wrlock(LOCK) \
257 (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
258 # define glthread_rwlock_unlock(LOCK) \
259 (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
260 # define glthread_rwlock_destroy(LOCK) \
261 (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
262 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
263 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
264 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
265 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
266 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
270 /* --------------------- gl_recursive_lock_t datatype --------------------- */
272 # if HAVE_PTHREAD_MUTEX_RECURSIVE
274 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
276 typedef pthread_mutex_t gl_recursive_lock_t;
277 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
278 STORAGECLASS pthread_mutex_t NAME;
279 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
280 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
281 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
282 # define gl_recursive_lock_initializer \
283 PTHREAD_RECURSIVE_MUTEX_INITIALIZER
285 # define gl_recursive_lock_initializer \
286 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
288 # define glthread_recursive_lock_init(LOCK) \
289 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
290 # define glthread_recursive_lock_lock(LOCK) \
291 (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
292 # define glthread_recursive_lock_unlock(LOCK) \
293 (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
294 # define glthread_recursive_lock_destroy(LOCK) \
295 (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
296 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
302 pthread_mutex_t recmutex; /* recursive mutex */
303 pthread_mutex_t guard; /* protects the initialization */
307 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
308 STORAGECLASS gl_recursive_lock_t NAME;
309 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
310 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
311 # define gl_recursive_lock_initializer \
312 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
313 # define glthread_recursive_lock_init(LOCK) \
314 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
315 # define glthread_recursive_lock_lock(LOCK) \
316 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
317 # define glthread_recursive_lock_unlock(LOCK) \
318 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
319 # define glthread_recursive_lock_destroy(LOCK) \
320 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
321 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
322 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
323 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
324 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
330 /* Old versions of POSIX threads on Solaris did not have recursive locks.
331 We have to implement them ourselves. */
335 pthread_mutex_t mutex;
340 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
341 STORAGECLASS gl_recursive_lock_t NAME;
342 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
343 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
344 # define gl_recursive_lock_initializer \
345 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
346 # define glthread_recursive_lock_init(LOCK) \
347 (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
348 # define glthread_recursive_lock_lock(LOCK) \
349 (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
350 # define glthread_recursive_lock_unlock(LOCK) \
351 (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
352 # define glthread_recursive_lock_destroy(LOCK) \
353 (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
354 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
355 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
356 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
357 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
361 /* -------------------------- gl_once_t datatype -------------------------- */
363 typedef pthread_once_t gl_once_t;
364 # define gl_once_define(STORAGECLASS, NAME) \
365 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
366 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
368 ? pthread_once (ONCE_CONTROL, INITFUNCTION) \
369 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
370 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
378 /* ========================================================================= */
382 /* Use the GNU Pth threads library. */
390 # if USE_PTH_THREADS_WEAK
392 /* Use weak references to the GNU Pth threads library. */
394 # pragma weak pth_mutex_init
395 # pragma weak pth_mutex_acquire
396 # pragma weak pth_mutex_release
397 # pragma weak pth_rwlock_init
398 # pragma weak pth_rwlock_acquire
399 # pragma weak pth_rwlock_release
400 # pragma weak pth_once
402 # pragma weak pth_cancel
403 # define pth_in_use() (pth_cancel != NULL)
407 # define pth_in_use() 1
411 /* -------------------------- gl_lock_t datatype -------------------------- */
413 typedef pth_mutex_t gl_lock_t;
414 # define gl_lock_define(STORAGECLASS, NAME) \
415 STORAGECLASS pth_mutex_t NAME;
416 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
417 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
418 # define gl_lock_initializer \
420 # define glthread_lock_init(LOCK) \
421 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
422 # define glthread_lock_lock(LOCK) \
423 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
424 # define glthread_lock_unlock(LOCK) \
425 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
426 # define glthread_lock_destroy(LOCK) \
429 /* ------------------------- gl_rwlock_t datatype ------------------------- */
431 typedef pth_rwlock_t gl_rwlock_t;
432 # define gl_rwlock_define(STORAGECLASS, NAME) \
433 STORAGECLASS pth_rwlock_t NAME;
434 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
435 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
436 # define gl_rwlock_initializer \
438 # define glthread_rwlock_init(LOCK) \
439 (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0)
440 # define glthread_rwlock_rdlock(LOCK) \
441 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0)
442 # define glthread_rwlock_wrlock(LOCK) \
443 (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0)
444 # define glthread_rwlock_unlock(LOCK) \
445 (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0)
446 # define glthread_rwlock_destroy(LOCK) \
449 /* --------------------- gl_recursive_lock_t datatype --------------------- */
451 /* In Pth, mutexes are recursive by default. */
452 typedef pth_mutex_t gl_recursive_lock_t;
453 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
454 STORAGECLASS pth_mutex_t NAME;
455 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
456 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
457 # define gl_recursive_lock_initializer \
459 # define glthread_recursive_lock_init(LOCK) \
460 (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
461 # define glthread_recursive_lock_lock(LOCK) \
462 (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
463 # define glthread_recursive_lock_unlock(LOCK) \
464 (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
465 # define glthread_recursive_lock_destroy(LOCK) \
468 /* -------------------------- gl_once_t datatype -------------------------- */
470 typedef pth_once_t gl_once_t;
471 # define gl_once_define(STORAGECLASS, NAME) \
472 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
473 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
475 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
476 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
477 extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void));
478 extern int glthread_once_singlethreaded (pth_once_t *once_control);
486 /* ========================================================================= */
488 #if USE_SOLARIS_THREADS
490 /* Use the old Solaris threads library. */
499 # if USE_SOLARIS_THREADS_WEAK
501 /* Use weak references to the old Solaris threads library. */
503 # pragma weak mutex_init
504 # pragma weak mutex_lock
505 # pragma weak mutex_unlock
506 # pragma weak mutex_destroy
507 # pragma weak rwlock_init
508 # pragma weak rw_rdlock
509 # pragma weak rw_wrlock
510 # pragma weak rw_unlock
511 # pragma weak rwlock_destroy
512 # pragma weak thr_self
514 # pragma weak thr_suspend
515 # define thread_in_use() (thr_suspend != NULL)
519 # define thread_in_use() 1
523 /* -------------------------- gl_lock_t datatype -------------------------- */
525 typedef mutex_t gl_lock_t;
526 # define gl_lock_define(STORAGECLASS, NAME) \
527 STORAGECLASS mutex_t NAME;
528 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
529 STORAGECLASS mutex_t NAME = gl_lock_initializer;
530 # define gl_lock_initializer \
532 # define glthread_lock_init(LOCK) \
533 (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
534 # define glthread_lock_lock(LOCK) \
535 (thread_in_use () ? mutex_lock (LOCK) : 0)
536 # define glthread_lock_unlock(LOCK) \
537 (thread_in_use () ? mutex_unlock (LOCK) : 0)
538 # define glthread_lock_destroy(LOCK) \
539 (thread_in_use () ? mutex_destroy (LOCK) : 0)
541 /* ------------------------- gl_rwlock_t datatype ------------------------- */
543 typedef rwlock_t gl_rwlock_t;
544 # define gl_rwlock_define(STORAGECLASS, NAME) \
545 STORAGECLASS rwlock_t NAME;
546 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
547 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
548 # define gl_rwlock_initializer \
550 # define glthread_rwlock_init(LOCK) \
551 (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
552 # define glthread_rwlock_rdlock(LOCK) \
553 (thread_in_use () ? rw_rdlock (LOCK) : 0)
554 # define glthread_rwlock_wrlock(LOCK) \
555 (thread_in_use () ? rw_wrlock (LOCK) : 0)
556 # define glthread_rwlock_unlock(LOCK) \
557 (thread_in_use () ? rw_unlock (LOCK) : 0)
558 # define glthread_rwlock_destroy(LOCK) \
559 (thread_in_use () ? rwlock_destroy (LOCK) : 0)
561 /* --------------------- gl_recursive_lock_t datatype --------------------- */
563 /* Old Solaris threads did not have recursive locks.
564 We have to implement them ourselves. */
573 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
574 STORAGECLASS gl_recursive_lock_t NAME;
575 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
576 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
577 # define gl_recursive_lock_initializer \
578 { DEFAULTMUTEX, (thread_t) 0, 0 }
579 # define glthread_recursive_lock_init(LOCK) \
580 (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
581 # define glthread_recursive_lock_lock(LOCK) \
582 (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
583 # define glthread_recursive_lock_unlock(LOCK) \
584 (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
585 # define glthread_recursive_lock_destroy(LOCK) \
586 (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
587 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
588 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
589 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
590 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
592 /* -------------------------- gl_once_t datatype -------------------------- */
600 # define gl_once_define(STORAGECLASS, NAME) \
601 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
602 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
604 ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
605 : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
606 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
607 extern int glthread_once_singlethreaded (gl_once_t *once_control);
615 /* ========================================================================= */
617 #if USE_WIN32_THREADS
619 # include <windows.h>
625 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
626 Semaphore types, because
627 - we need only to synchronize inside a single process (address space),
628 not inter-process locking,
629 - we don't need to support trylock operations. (TryEnterCriticalSection
630 does not work on Windows 95/98/ME. Packages that need trylock usually
631 define their own mutex type.) */
633 /* There is no way to statically initialize a CRITICAL_SECTION. It needs
634 to be done lazily, once only. For this we need spinlocks. */
636 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
638 /* -------------------------- gl_lock_t datatype -------------------------- */
642 gl_spinlock_t guard; /* protects the initialization */
643 CRITICAL_SECTION lock;
646 # define gl_lock_define(STORAGECLASS, NAME) \
647 STORAGECLASS gl_lock_t NAME;
648 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
649 STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
650 # define gl_lock_initializer \
652 # define glthread_lock_init(LOCK) \
653 (glthread_lock_init_func (LOCK), 0)
654 # define glthread_lock_lock(LOCK) \
655 glthread_lock_lock_func (LOCK)
656 # define glthread_lock_unlock(LOCK) \
657 glthread_lock_unlock_func (LOCK)
658 # define glthread_lock_destroy(LOCK) \
659 glthread_lock_destroy_func (LOCK)
660 extern void glthread_lock_init_func (gl_lock_t *lock);
661 extern int glthread_lock_lock_func (gl_lock_t *lock);
662 extern int glthread_lock_unlock_func (gl_lock_t *lock);
663 extern int glthread_lock_destroy_func (gl_lock_t *lock);
665 /* ------------------------- gl_rwlock_t datatype ------------------------- */
667 /* It is impossible to implement read-write locks using plain locks, without
668 introducing an extra thread dedicated to managing read-write locks.
669 Therefore here we need to use the low-level Event type. */
673 HANDLE *array; /* array of waiting threads, each represented by an event */
674 unsigned int count; /* number of waiting threads */
675 unsigned int alloc; /* length of allocated array */
676 unsigned int offset; /* index of first waiting thread in array */
678 gl_carray_waitqueue_t;
681 gl_spinlock_t guard; /* protects the initialization */
682 CRITICAL_SECTION lock; /* protects the remaining fields */
683 gl_carray_waitqueue_t waiting_readers; /* waiting readers */
684 gl_carray_waitqueue_t waiting_writers; /* waiting writers */
685 int runcount; /* number of readers running, or -1 when a writer runs */
688 # define gl_rwlock_define(STORAGECLASS, NAME) \
689 STORAGECLASS gl_rwlock_t NAME;
690 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
691 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
692 # define gl_rwlock_initializer \
694 # define glthread_rwlock_init(LOCK) \
695 (glthread_rwlock_init_func (LOCK), 0)
696 # define glthread_rwlock_rdlock(LOCK) \
697 glthread_rwlock_rdlock_func (LOCK)
698 # define glthread_rwlock_wrlock(LOCK) \
699 glthread_rwlock_wrlock_func (LOCK)
700 # define glthread_rwlock_unlock(LOCK) \
701 glthread_rwlock_unlock_func (LOCK)
702 # define glthread_rwlock_destroy(LOCK) \
703 glthread_rwlock_destroy_func (LOCK)
704 extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
705 extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock);
706 extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock);
707 extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock);
708 extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock);
710 /* --------------------- gl_recursive_lock_t datatype --------------------- */
712 /* The Win32 documentation says that CRITICAL_SECTION already implements a
713 recursive lock. But we need not rely on it: It's easy to implement a
714 recursive lock without this assumption. */
718 gl_spinlock_t guard; /* protects the initialization */
721 CRITICAL_SECTION lock;
724 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
725 STORAGECLASS gl_recursive_lock_t NAME;
726 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
727 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
728 # define gl_recursive_lock_initializer \
730 # define glthread_recursive_lock_init(LOCK) \
731 (glthread_recursive_lock_init_func (LOCK), 0)
732 # define glthread_recursive_lock_lock(LOCK) \
733 glthread_recursive_lock_lock_func (LOCK)
734 # define glthread_recursive_lock_unlock(LOCK) \
735 glthread_recursive_lock_unlock_func (LOCK)
736 # define glthread_recursive_lock_destroy(LOCK) \
737 glthread_recursive_lock_destroy_func (LOCK)
738 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
739 extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock);
740 extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock);
741 extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock);
743 /* -------------------------- gl_once_t datatype -------------------------- */
748 volatile long started;
749 CRITICAL_SECTION lock;
752 # define gl_once_define(STORAGECLASS, NAME) \
753 STORAGECLASS gl_once_t NAME = { -1, -1 };
754 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
755 (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
756 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
764 /* ========================================================================= */
766 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
768 /* Provide dummy implementation if threads are not supported. */
770 /* -------------------------- gl_lock_t datatype -------------------------- */
772 typedef int gl_lock_t;
773 # define gl_lock_define(STORAGECLASS, NAME)
774 # define gl_lock_define_initialized(STORAGECLASS, NAME)
775 # define glthread_lock_init(NAME) 0
776 # define glthread_lock_lock(NAME) 0
777 # define glthread_lock_unlock(NAME) 0
778 # define glthread_lock_destroy(NAME) 0
780 /* ------------------------- gl_rwlock_t datatype ------------------------- */
782 typedef int gl_rwlock_t;
783 # define gl_rwlock_define(STORAGECLASS, NAME)
784 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
785 # define glthread_rwlock_init(NAME) 0
786 # define glthread_rwlock_rdlock(NAME) 0
787 # define glthread_rwlock_wrlock(NAME) 0
788 # define glthread_rwlock_unlock(NAME) 0
789 # define glthread_rwlock_destroy(NAME) 0
791 /* --------------------- gl_recursive_lock_t datatype --------------------- */
793 typedef int gl_recursive_lock_t;
794 # define gl_recursive_lock_define(STORAGECLASS, NAME)
795 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
796 # define glthread_recursive_lock_init(NAME) 0
797 # define glthread_recursive_lock_lock(NAME) 0
798 # define glthread_recursive_lock_unlock(NAME) 0
799 # define glthread_recursive_lock_destroy(NAME) 0
801 /* -------------------------- gl_once_t datatype -------------------------- */
803 typedef int gl_once_t;
804 # define gl_once_define(STORAGECLASS, NAME) \
805 STORAGECLASS gl_once_t NAME = 0;
806 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
807 (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
811 /* ========================================================================= */
813 /* Macros with built-in error handling. */
815 /* -------------------------- gl_lock_t datatype -------------------------- */
817 #define gl_lock_init(NAME) \
820 if (glthread_lock_init (&NAME)) \
824 #define gl_lock_lock(NAME) \
827 if (glthread_lock_lock (&NAME)) \
831 #define gl_lock_unlock(NAME) \
834 if (glthread_lock_unlock (&NAME)) \
838 #define gl_lock_destroy(NAME) \
841 if (glthread_lock_destroy (&NAME)) \
846 /* ------------------------- gl_rwlock_t datatype ------------------------- */
848 #define gl_rwlock_init(NAME) \
851 if (glthread_rwlock_init (&NAME)) \
855 #define gl_rwlock_rdlock(NAME) \
858 if (glthread_rwlock_rdlock (&NAME)) \
862 #define gl_rwlock_wrlock(NAME) \
865 if (glthread_rwlock_wrlock (&NAME)) \
869 #define gl_rwlock_unlock(NAME) \
872 if (glthread_rwlock_unlock (&NAME)) \
876 #define gl_rwlock_destroy(NAME) \
879 if (glthread_rwlock_destroy (&NAME)) \
884 /* --------------------- gl_recursive_lock_t datatype --------------------- */
886 #define gl_recursive_lock_init(NAME) \
889 if (glthread_recursive_lock_init (&NAME)) \
893 #define gl_recursive_lock_lock(NAME) \
896 if (glthread_recursive_lock_lock (&NAME)) \
900 #define gl_recursive_lock_unlock(NAME) \
903 if (glthread_recursive_lock_unlock (&NAME)) \
907 #define gl_recursive_lock_destroy(NAME) \
910 if (glthread_recursive_lock_destroy (&NAME)) \
915 /* -------------------------- gl_once_t datatype -------------------------- */
917 #define gl_once(NAME, INITFUNCTION) \
920 if (glthread_once (&NAME, INITFUNCTION)) \
925 /* ========================================================================= */