1 /* Locking in multithreaded situations.
2 Copyright (C) 2005 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 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
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);
35 Read-Write (non-recursive) locks:
37 Declaration: gl_rwlock_define(extern, name)
38 Initializer: gl_rwlock_define_initialized(, name)
39 Initialization: gl_rwlock_init (name);
40 Taking the lock: gl_rwlock_rdlock (name);
41 gl_rwlock_wrlock (name);
42 Releasing the lock: gl_rwlock_unlock (name);
43 De-initialization: gl_rwlock_destroy (name);
46 Type: gl_recursive_lock_t
47 Declaration: gl_recursive_lock_define(extern, name)
48 Initializer: gl_recursive_lock_define_initialized(, name)
49 Initialization: gl_recursive_lock_init (name);
50 Taking the lock: gl_recursive_lock_lock (name);
51 Releasing the lock: gl_recursive_lock_unlock (name);
52 De-initialization: gl_recursive_lock_destroy (name);
56 Initializer: gl_once_define(extern, name)
57 Execution: gl_once (name, initfunction);
64 /* ========================================================================= */
68 /* Use the POSIX threads library. */
73 # if PTHREAD_IN_USE_DETECTION_HARD
75 /* The pthread_in_use() detection needs to be done at runtime. */
76 # define pthread_in_use() \
78 extern int glthread_in_use (void);
82 # if USE_POSIX_THREADS_WEAK
84 /* Use weak references to the POSIX threads library. */
86 /* Weak references avoid dragging in external libraries if the other parts
87 of the program don't use them. Here we use them, because we don't want
88 every program that uses libintl to depend on libpthread. This assumes
89 that libpthread would not be loaded after libintl; i.e. if libintl is
90 loaded first, by an executable that does not depend on libpthread, and
91 then a module is dynamically loaded that depends on libpthread, libintl
92 will not be multithread-safe. */
94 /* The way to test at runtime whether libpthread is present is to test
95 whether a function pointer's value, such as &pthread_mutex_init, is
96 non-NULL. However, some versions of GCC have a bug through which, in
97 PIC mode, &foo != NULL always evaluates to true if there is a direct
98 call to foo(...) in the same function. To avoid this, we test the
99 address of a function in libpthread that we don't use. */
101 # pragma weak pthread_mutex_init
102 # pragma weak pthread_mutex_lock
103 # pragma weak pthread_mutex_unlock
104 # pragma weak pthread_mutex_destroy
105 # pragma weak pthread_rwlock_init
106 # pragma weak pthread_rwlock_rdlock
107 # pragma weak pthread_rwlock_wrlock
108 # pragma weak pthread_rwlock_unlock
109 # pragma weak pthread_rwlock_destroy
110 # pragma weak pthread_once
111 # pragma weak pthread_cond_init
112 # pragma weak pthread_cond_wait
113 # pragma weak pthread_cond_signal
114 # pragma weak pthread_cond_broadcast
115 # pragma weak pthread_cond_destroy
116 # pragma weak pthread_mutexattr_init
117 # pragma weak pthread_mutexattr_settype
118 # pragma weak pthread_mutexattr_destroy
119 # ifndef pthread_self
120 # pragma weak pthread_self
123 # if !PTHREAD_IN_USE_DETECTION_HARD
124 # pragma weak pthread_cancel
125 # define pthread_in_use() (pthread_cancel != NULL)
130 # if !PTHREAD_IN_USE_DETECTION_HARD
131 # define pthread_in_use() 1
136 /* -------------------------- gl_lock_t datatype -------------------------- */
138 typedef pthread_mutex_t gl_lock_t;
139 # define gl_lock_define(STORAGECLASS, NAME) \
140 STORAGECLASS pthread_mutex_t NAME;
141 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
142 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
143 # define gl_lock_initializer \
144 PTHREAD_MUTEX_INITIALIZER
145 # define gl_lock_init(NAME) \
146 if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
147 # define gl_lock_lock(NAME) \
148 if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
149 # define gl_lock_unlock(NAME) \
150 if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
151 # define gl_lock_destroy(NAME) \
152 if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
154 /* ------------------------- gl_rwlock_t datatype ------------------------- */
156 # if HAVE_PTHREAD_RWLOCK
158 # ifdef PTHREAD_RWLOCK_INITIALIZER
160 typedef pthread_rwlock_t gl_rwlock_t;
161 # define gl_rwlock_define(STORAGECLASS, NAME) \
162 STORAGECLASS pthread_rwlock_t NAME;
163 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
164 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
165 # define gl_rwlock_initializer \
166 PTHREAD_RWLOCK_INITIALIZER
167 # define gl_rwlock_init(NAME) \
168 if (pthread_in_use () && pthread_rwlock_init (&NAME, NULL) != 0) abort ()
169 # define gl_rwlock_rdlock(NAME) \
170 if (pthread_in_use () && pthread_rwlock_rdlock (&NAME) != 0) abort ()
171 # define gl_rwlock_wrlock(NAME) \
172 if (pthread_in_use () && pthread_rwlock_wrlock (&NAME) != 0) abort ()
173 # define gl_rwlock_unlock(NAME) \
174 if (pthread_in_use () && pthread_rwlock_unlock (&NAME) != 0) abort ()
175 # define gl_rwlock_destroy(NAME) \
176 if (pthread_in_use () && pthread_rwlock_destroy (&NAME) != 0) abort ()
183 pthread_mutex_t guard; /* protects the initialization */
184 pthread_rwlock_t rwlock; /* read-write lock */
187 # define gl_rwlock_define(STORAGECLASS, NAME) \
188 STORAGECLASS gl_rwlock_t NAME;
189 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
190 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
191 # define gl_rwlock_initializer \
192 { 0, PTHREAD_MUTEX_INITIALIZER }
193 # define gl_rwlock_init(NAME) \
194 if (pthread_in_use ()) glthread_rwlock_init (&NAME)
195 # define gl_rwlock_rdlock(NAME) \
196 if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
197 # define gl_rwlock_wrlock(NAME) \
198 if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
199 # define gl_rwlock_unlock(NAME) \
200 if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
201 # define gl_rwlock_destroy(NAME) \
202 if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
203 extern void glthread_rwlock_init (gl_rwlock_t *lock);
204 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
205 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
206 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
207 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
215 pthread_mutex_t lock; /* protects the remaining fields */
216 pthread_cond_t waiting_readers; /* waiting readers */
217 pthread_cond_t waiting_writers; /* waiting writers */
218 unsigned int waiting_writers_count; /* number of waiting writers */
219 int runcount; /* number of readers running, or -1 when a writer runs */
222 # define gl_rwlock_define(STORAGECLASS, NAME) \
223 STORAGECLASS gl_rwlock_t NAME;
224 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
225 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
226 # define gl_rwlock_initializer \
227 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
228 # define gl_rwlock_init(NAME) \
229 if (pthread_in_use ()) glthread_rwlock_init (&NAME)
230 # define gl_rwlock_rdlock(NAME) \
231 if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
232 # define gl_rwlock_wrlock(NAME) \
233 if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
234 # define gl_rwlock_unlock(NAME) \
235 if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
236 # define gl_rwlock_destroy(NAME) \
237 if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
238 extern void glthread_rwlock_init (gl_rwlock_t *lock);
239 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
240 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
241 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
242 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
246 /* --------------------- gl_recursive_lock_t datatype --------------------- */
248 # if HAVE_PTHREAD_MUTEX_RECURSIVE
250 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
252 typedef pthread_mutex_t gl_recursive_lock_t;
253 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
254 STORAGECLASS pthread_mutex_t NAME;
255 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
256 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
257 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
258 # define gl_recursive_lock_initializer \
259 PTHREAD_RECURSIVE_MUTEX_INITIALIZER
261 # define gl_recursive_lock_initializer \
262 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
264 # define gl_recursive_lock_init(NAME) \
265 if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
266 # define gl_recursive_lock_lock(NAME) \
267 if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
268 # define gl_recursive_lock_unlock(NAME) \
269 if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
270 # define gl_recursive_lock_destroy(NAME) \
271 if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
277 pthread_mutex_t recmutex; /* recursive mutex */
278 pthread_mutex_t guard; /* protects the initialization */
282 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
283 STORAGECLASS gl_recursive_lock_t NAME;
284 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
285 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
286 # define gl_recursive_lock_initializer \
287 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
288 # define gl_recursive_lock_init(NAME) \
289 if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
290 # define gl_recursive_lock_lock(NAME) \
291 if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
292 # define gl_recursive_lock_unlock(NAME) \
293 if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
294 # define gl_recursive_lock_destroy(NAME) \
295 if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
296 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
297 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
298 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
299 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
305 /* Old versions of POSIX threads on Solaris did not have recursive locks.
306 We have to implement them ourselves. */
310 pthread_mutex_t mutex;
315 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
316 STORAGECLASS gl_recursive_lock_t NAME;
317 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
318 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
319 # define gl_recursive_lock_initializer \
320 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
321 # define gl_recursive_lock_init(NAME) \
322 if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
323 # define gl_recursive_lock_lock(NAME) \
324 if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
325 # define gl_recursive_lock_unlock(NAME) \
326 if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
327 # define gl_recursive_lock_destroy(NAME) \
328 if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
329 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
330 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
331 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
332 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
336 /* -------------------------- gl_once_t datatype -------------------------- */
338 typedef pthread_once_t gl_once_t;
339 # define gl_once_define(STORAGECLASS, NAME) \
340 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
341 # define gl_once(NAME, INITFUNCTION) \
344 if (pthread_in_use ()) \
346 if (pthread_once (&NAME, INITFUNCTION) != 0) \
351 if (glthread_once_singlethreaded (&NAME)) \
356 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
360 /* ========================================================================= */
364 /* Use the GNU Pth threads library. */
369 # if USE_PTH_THREADS_WEAK
371 /* Use weak references to the GNU Pth threads library. */
373 # pragma weak pth_mutex_init
374 # pragma weak pth_mutex_acquire
375 # pragma weak pth_mutex_release
376 # pragma weak pth_rwlock_init
377 # pragma weak pth_rwlock_acquire
378 # pragma weak pth_rwlock_release
379 # pragma weak pth_once
381 # pragma weak pth_cancel
382 # define pth_in_use() (pth_cancel != NULL)
386 # define pth_in_use() 1
390 /* -------------------------- gl_lock_t datatype -------------------------- */
392 typedef pth_mutex_t gl_lock_t;
393 # define gl_lock_define(STORAGECLASS, NAME) \
394 STORAGECLASS pth_mutex_t NAME;
395 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
396 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
397 # define gl_lock_initializer \
399 # define gl_lock_init(NAME) \
400 if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
401 # define gl_lock_lock(NAME) \
402 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
403 # define gl_lock_unlock(NAME) \
404 if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
405 # define gl_lock_destroy(NAME) \
408 /* ------------------------- gl_rwlock_t datatype ------------------------- */
410 typedef pth_rwlock_t gl_rwlock_t;
411 # define gl_rwlock_define(STORAGECLASS, NAME) \
412 STORAGECLASS pth_rwlock_t NAME;
413 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
414 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
415 # define gl_rwlock_initializer \
417 # define gl_rwlock_init(NAME) \
418 if (pth_in_use() && !pth_rwlock_init (&NAME)) abort ()
419 # define gl_rwlock_rdlock(NAME) \
420 if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) abort ()
421 # define gl_rwlock_wrlock(NAME) \
422 if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) abort ()
423 # define gl_rwlock_unlock(NAME) \
424 if (pth_in_use() && !pth_rwlock_release (&NAME)) abort ()
425 # define gl_rwlock_destroy(NAME) \
428 /* --------------------- gl_recursive_lock_t datatype --------------------- */
430 /* In Pth, mutexes are recursive by default. */
431 typedef pth_mutex_t gl_recursive_lock_t;
432 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
433 STORAGECLASS pth_mutex_t NAME;
434 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
435 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
436 # define gl_recursive_lock_initializer \
438 # define gl_recursive_lock_init(NAME) \
439 if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
440 # define gl_recursive_lock_lock(NAME) \
441 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
442 # define gl_recursive_lock_unlock(NAME) \
443 if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
444 # define gl_recursive_lock_destroy(NAME) \
447 /* -------------------------- gl_once_t datatype -------------------------- */
449 typedef pth_once_t gl_once_t;
450 # define gl_once_define(STORAGECLASS, NAME) \
451 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
452 # define gl_once(NAME, INITFUNCTION) \
457 void (*gl_once_temp) (void) = INITFUNCTION; \
458 if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
463 if (glthread_once_singlethreaded (&NAME)) \
468 extern void glthread_once_call (void *arg);
469 extern int glthread_once_singlethreaded (pth_once_t *once_control);
473 /* ========================================================================= */
475 #if USE_SOLARIS_THREADS
477 /* Use the old Solaris threads library. */
483 # if USE_SOLARIS_THREADS_WEAK
485 /* Use weak references to the old Solaris threads library. */
487 # pragma weak mutex_init
488 # pragma weak mutex_lock
489 # pragma weak mutex_unlock
490 # pragma weak mutex_destroy
491 # pragma weak rwlock_init
492 # pragma weak rw_rdlock
493 # pragma weak rw_wrlock
494 # pragma weak rw_unlock
495 # pragma weak rwlock_destroy
496 # pragma weak thr_self
498 # pragma weak thr_suspend
499 # define thread_in_use() (thr_suspend != NULL)
503 # define thread_in_use() 1
507 /* -------------------------- gl_lock_t datatype -------------------------- */
509 typedef mutex_t gl_lock_t;
510 # define gl_lock_define(STORAGECLASS, NAME) \
511 STORAGECLASS mutex_t NAME;
512 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
513 STORAGECLASS mutex_t NAME = gl_lock_initializer;
514 # define gl_lock_initializer \
516 # define gl_lock_init(NAME) \
517 if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
518 # define gl_lock_lock(NAME) \
519 if (thread_in_use () && mutex_lock (&NAME) != 0) abort ()
520 # define gl_lock_unlock(NAME) \
521 if (thread_in_use () && mutex_unlock (&NAME) != 0) abort ()
522 # define gl_lock_destroy(NAME) \
523 if (thread_in_use () && mutex_destroy (&NAME) != 0) abort ()
525 /* ------------------------- gl_rwlock_t datatype ------------------------- */
527 typedef rwlock_t gl_rwlock_t;
528 # define gl_rwlock_define(STORAGECLASS, NAME) \
529 STORAGECLASS rwlock_t NAME;
530 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
531 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
532 # define gl_rwlock_initializer \
534 # define gl_rwlock_init(NAME) \
535 if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
536 # define gl_rwlock_rdlock(NAME) \
537 if (thread_in_use () && rw_rdlock (&NAME) != 0) abort ()
538 # define gl_rwlock_wrlock(NAME) \
539 if (thread_in_use () && rw_wrlock (&NAME) != 0) abort ()
540 # define gl_rwlock_unlock(NAME) \
541 if (thread_in_use () && rw_unlock (&NAME) != 0) abort ()
542 # define gl_rwlock_destroy(NAME) \
543 if (thread_in_use () && rwlock_destroy (&NAME) != 0) abort ()
545 /* --------------------- gl_recursive_lock_t datatype --------------------- */
547 /* Old Solaris threads did not have recursive locks.
548 We have to implement them ourselves. */
557 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
558 STORAGECLASS gl_recursive_lock_t NAME;
559 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
560 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
561 # define gl_recursive_lock_initializer \
562 { DEFAULTMUTEX, (thread_t) 0, 0 }
563 # define gl_recursive_lock_init(NAME) \
564 if (thread_in_use ()) glthread_recursive_lock_init (&NAME)
565 # define gl_recursive_lock_lock(NAME) \
566 if (thread_in_use ()) glthread_recursive_lock_lock (&NAME)
567 # define gl_recursive_lock_unlock(NAME) \
568 if (thread_in_use ()) glthread_recursive_lock_unlock (&NAME)
569 # define gl_recursive_lock_destroy(NAME) \
570 if (thread_in_use ()) glthread_recursive_lock_destroy (&NAME)
571 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
572 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
573 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
574 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
576 /* -------------------------- gl_once_t datatype -------------------------- */
584 # define gl_once_define(STORAGECLASS, NAME) \
585 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
586 # define gl_once(NAME, INITFUNCTION) \
589 if (thread_in_use ()) \
591 glthread_once (&NAME, INITFUNCTION); \
595 if (glthread_once_singlethreaded (&NAME)) \
600 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
601 extern int glthread_once_singlethreaded (gl_once_t *once_control);
605 /* ========================================================================= */
607 #if USE_WIN32_THREADS
609 # include <windows.h>
611 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
612 Semaphore types, because
613 - we need only to synchronize inside a single process (address space),
614 not inter-process locking,
615 - we don't need to support trylock operations. (TryEnterCriticalSection
616 does not work on Windows 95/98/ME. Packages that need trylock usually
617 define their own mutex type.) */
619 /* There is no way to statically initialize a CRITICAL_SECTION. It needs
620 to be done lazily, once only. For this we need spinlocks. */
622 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
624 /* -------------------------- gl_lock_t datatype -------------------------- */
628 gl_spinlock_t guard; /* protects the initialization */
629 CRITICAL_SECTION lock;
632 # define gl_lock_define(STORAGECLASS, NAME) \
633 STORAGECLASS gl_lock_t NAME;
634 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
635 STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
636 # define gl_lock_initializer \
638 # define gl_lock_init(NAME) \
639 glthread_lock_init (&NAME)
640 # define gl_lock_lock(NAME) \
641 glthread_lock_lock (&NAME)
642 # define gl_lock_unlock(NAME) \
643 glthread_lock_unlock (&NAME)
644 # define gl_lock_destroy(NAME) \
645 glthread_lock_destroy (&NAME)
646 extern void glthread_lock_init (gl_lock_t *lock);
647 extern void glthread_lock_lock (gl_lock_t *lock);
648 extern void glthread_lock_unlock (gl_lock_t *lock);
649 extern void glthread_lock_destroy (gl_lock_t *lock);
651 /* ------------------------- gl_rwlock_t datatype ------------------------- */
653 /* It is impossible to implement read-write locks using plain locks, without
654 introducing an extra thread dedicated to managing read-write locks.
655 Therefore here we need to use the low-level Event type. */
659 HANDLE *array; /* array of waiting threads, each represented by an event */
660 unsigned int count; /* number of waiting threads */
661 unsigned int alloc; /* length of allocated array */
662 unsigned int offset; /* index of first waiting thread in array */
667 gl_spinlock_t guard; /* protects the initialization */
668 CRITICAL_SECTION lock; /* protects the remaining fields */
669 gl_waitqueue_t waiting_readers; /* waiting readers */
670 gl_waitqueue_t waiting_writers; /* waiting writers */
671 int runcount; /* number of readers running, or -1 when a writer runs */
674 # define gl_rwlock_define(STORAGECLASS, NAME) \
675 STORAGECLASS gl_rwlock_t NAME;
676 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
677 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
678 # define gl_rwlock_initializer \
680 # define gl_rwlock_init(NAME) \
681 glthread_rwlock_init (&NAME)
682 # define gl_rwlock_rdlock(NAME) \
683 glthread_rwlock_rdlock (&NAME)
684 # define gl_rwlock_wrlock(NAME) \
685 glthread_rwlock_wrlock (&NAME)
686 # define gl_rwlock_unlock(NAME) \
687 glthread_rwlock_unlock (&NAME)
688 # define gl_rwlock_destroy(NAME) \
689 glthread_rwlock_destroy (&NAME)
690 extern void glthread_rwlock_init (gl_rwlock_t *lock);
691 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
692 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
693 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
694 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
696 /* --------------------- gl_recursive_lock_t datatype --------------------- */
698 /* The Win32 documentation says that CRITICAL_SECTION already implements a
699 recursive lock. But we need not rely on it: It's easy to implement a
700 recursive lock without this assumption. */
704 gl_spinlock_t guard; /* protects the initialization */
707 CRITICAL_SECTION lock;
710 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
711 STORAGECLASS gl_recursive_lock_t NAME;
712 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
713 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
714 # define gl_recursive_lock_initializer \
716 # define gl_recursive_lock_init(NAME) \
717 glthread_recursive_lock_init (&NAME)
718 # define gl_recursive_lock_lock(NAME) \
719 glthread_recursive_lock_lock (&NAME)
720 # define gl_recursive_lock_unlock(NAME) \
721 glthread_recursive_lock_unlock (&NAME)
722 # define gl_recursive_lock_destroy(NAME) \
723 glthread_recursive_lock_destroy (&NAME)
724 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
725 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
726 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
727 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
729 /* -------------------------- gl_once_t datatype -------------------------- */
734 volatile long started;
735 CRITICAL_SECTION lock;
738 # define gl_once_define(STORAGECLASS, NAME) \
739 STORAGECLASS gl_once_t NAME = { -1, -1 };
740 # define gl_once(NAME, INITFUNCTION) \
741 glthread_once (&NAME, INITFUNCTION)
742 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
746 /* ========================================================================= */
748 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
750 /* Provide dummy implementation if threads are not supported. */
752 /* -------------------------- gl_lock_t datatype -------------------------- */
754 typedef int gl_lock_t;
755 # define gl_lock_define(STORAGECLASS, NAME)
756 # define gl_lock_define_initialized(STORAGECLASS, NAME)
757 # define gl_lock_init(NAME)
758 # define gl_lock_lock(NAME)
759 # define gl_lock_unlock(NAME)
761 /* ------------------------- gl_rwlock_t datatype ------------------------- */
763 typedef int gl_rwlock_t;
764 # define gl_rwlock_define(STORAGECLASS, NAME)
765 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
766 # define gl_rwlock_init(NAME)
767 # define gl_rwlock_rdlock(NAME)
768 # define gl_rwlock_wrlock(NAME)
769 # define gl_rwlock_unlock(NAME)
771 /* --------------------- gl_recursive_lock_t datatype --------------------- */
773 typedef int gl_recursive_lock_t;
774 # define gl_recursive_lock_define(STORAGECLASS, NAME)
775 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
776 # define gl_recursive_lock_init(NAME)
777 # define gl_recursive_lock_lock(NAME)
778 # define gl_recursive_lock_unlock(NAME)
780 /* -------------------------- gl_once_t datatype -------------------------- */
782 typedef int gl_once_t;
783 # define gl_once_define(STORAGECLASS, NAME) \
784 STORAGECLASS gl_once_t NAME = 0;
785 # define gl_once(NAME, INITFUNCTION) \
798 /* ========================================================================= */