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 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);
36 Read-Write (non-recursive) locks:
38 Declaration: gl_rwlock_define(extern, name)
39 Initializer: gl_rwlock_define_initialized(, name)
40 Initialization: gl_rwlock_init (name);
41 Taking the lock: gl_rwlock_rdlock (name);
42 gl_rwlock_wrlock (name);
43 Releasing the lock: gl_rwlock_unlock (name);
44 De-initialization: gl_rwlock_destroy (name);
47 Type: gl_recursive_lock_t
48 Declaration: gl_recursive_lock_define(extern, name)
49 Initializer: gl_recursive_lock_define_initialized(, name)
50 Initialization: gl_recursive_lock_init (name);
51 Taking the lock: gl_recursive_lock_lock (name);
52 Releasing the lock: gl_recursive_lock_unlock (name);
53 De-initialization: gl_recursive_lock_destroy (name);
57 Initializer: gl_once_define(extern, name)
58 Execution: gl_once (name, initfunction);
62 /* ========================================================================= */
66 /* Use the POSIX threads library. */
71 # if PTHREAD_IN_USE_DETECTION_HARD
73 /* The pthread_in_use() detection needs to be done at runtime. */
74 # define pthread_in_use() \
76 extern int glthread_in_use (void);
80 # if USE_POSIX_THREADS_WEAK
82 /* Use weak references to the POSIX threads library. */
84 /* Weak references avoid dragging in external libraries if the other parts
85 of the program don't use them. Here we use them, because we don't want
86 every program that uses libintl to depend on libpthread. This assumes
87 that libpthread would not be loaded after libintl; i.e. if libintl is
88 loaded first, by an executable that does not depend on libpthread, and
89 then a module is dynamically loaded that depends on libpthread, libintl
90 will not be multithread-safe. */
92 /* The way to test at runtime whether libpthread is present is to test
93 whether a function pointer's value, such as &pthread_mutex_init, is
94 non-NULL. However, some versions of GCC have a bug through which, in
95 PIC mode, &foo != NULL always evaluates to true if there is a direct
96 call to foo(...) in the same function. To avoid this, we test the
97 address of a function in libpthread that we don't use. */
99 # pragma weak pthread_mutex_init
100 # pragma weak pthread_mutex_lock
101 # pragma weak pthread_mutex_unlock
102 # pragma weak pthread_mutex_destroy
103 # pragma weak pthread_rwlock_init
104 # pragma weak pthread_rwlock_rdlock
105 # pragma weak pthread_rwlock_wrlock
106 # pragma weak pthread_rwlock_unlock
107 # pragma weak pthread_rwlock_destroy
108 # pragma weak pthread_once
109 # pragma weak pthread_cond_init
110 # pragma weak pthread_cond_wait
111 # pragma weak pthread_cond_signal
112 # pragma weak pthread_cond_broadcast
113 # pragma weak pthread_cond_destroy
114 # pragma weak pthread_mutexattr_init
115 # pragma weak pthread_mutexattr_settype
116 # pragma weak pthread_mutexattr_destroy
117 # ifndef pthread_self
118 # pragma weak pthread_self
121 # if !PTHREAD_IN_USE_DETECTION_HARD
122 # pragma weak pthread_cancel
123 # define pthread_in_use() (pthread_cancel != NULL)
128 # if !PTHREAD_IN_USE_DETECTION_HARD
129 # define pthread_in_use() 1
134 /* -------------------------- gl_lock_t datatype -------------------------- */
136 typedef pthread_mutex_t gl_lock_t;
137 # define gl_lock_define(STORAGECLASS, NAME) \
138 STORAGECLASS pthread_mutex_t NAME;
139 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
140 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
141 # define gl_lock_initializer \
142 PTHREAD_MUTEX_INITIALIZER
143 # define gl_lock_init(NAME) \
144 if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
145 # define gl_lock_lock(NAME) \
146 if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
147 # define gl_lock_unlock(NAME) \
148 if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
149 # define gl_lock_destroy(NAME) \
150 if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
152 /* ------------------------- gl_rwlock_t datatype ------------------------- */
154 # if HAVE_PTHREAD_RWLOCK
156 # ifdef PTHREAD_RWLOCK_INITIALIZER
158 typedef pthread_rwlock_t gl_rwlock_t;
159 # define gl_rwlock_define(STORAGECLASS, NAME) \
160 STORAGECLASS pthread_rwlock_t NAME;
161 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
162 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
163 # define gl_rwlock_initializer \
164 PTHREAD_RWLOCK_INITIALIZER
165 # define gl_rwlock_init(NAME) \
166 if (pthread_in_use () && pthread_rwlock_init (&NAME, NULL) != 0) abort ()
167 # define gl_rwlock_rdlock(NAME) \
168 if (pthread_in_use () && pthread_rwlock_rdlock (&NAME) != 0) abort ()
169 # define gl_rwlock_wrlock(NAME) \
170 if (pthread_in_use () && pthread_rwlock_wrlock (&NAME) != 0) abort ()
171 # define gl_rwlock_unlock(NAME) \
172 if (pthread_in_use () && pthread_rwlock_unlock (&NAME) != 0) abort ()
173 # define gl_rwlock_destroy(NAME) \
174 if (pthread_in_use () && pthread_rwlock_destroy (&NAME) != 0) abort ()
181 pthread_mutex_t guard; /* protects the initialization */
182 pthread_rwlock_t rwlock; /* read-write lock */
185 # define gl_rwlock_define(STORAGECLASS, NAME) \
186 STORAGECLASS gl_rwlock_t NAME;
187 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
188 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
189 # define gl_rwlock_initializer \
190 { 0, PTHREAD_MUTEX_INITIALIZER }
191 # define gl_rwlock_init(NAME) \
192 if (pthread_in_use ()) glthread_rwlock_init (&NAME)
193 # define gl_rwlock_rdlock(NAME) \
194 if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
195 # define gl_rwlock_wrlock(NAME) \
196 if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
197 # define gl_rwlock_unlock(NAME) \
198 if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
199 # define gl_rwlock_destroy(NAME) \
200 if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
201 extern void glthread_rwlock_init (gl_rwlock_t *lock);
202 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
203 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
204 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
205 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
213 pthread_mutex_t lock; /* protects the remaining fields */
214 pthread_cond_t waiting_readers; /* waiting readers */
215 pthread_cond_t waiting_writers; /* waiting writers */
216 unsigned int waiting_writers_count; /* number of waiting writers */
217 int runcount; /* number of readers running, or -1 when a writer runs */
220 # define gl_rwlock_define(STORAGECLASS, NAME) \
221 STORAGECLASS gl_rwlock_t NAME;
222 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
223 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
224 # define gl_rwlock_initializer \
225 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
226 # define gl_rwlock_init(NAME) \
227 if (pthread_in_use ()) glthread_rwlock_init (&NAME)
228 # define gl_rwlock_rdlock(NAME) \
229 if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
230 # define gl_rwlock_wrlock(NAME) \
231 if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
232 # define gl_rwlock_unlock(NAME) \
233 if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
234 # define gl_rwlock_destroy(NAME) \
235 if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
236 extern void glthread_rwlock_init (gl_rwlock_t *lock);
237 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
238 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
239 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
240 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
244 /* --------------------- gl_recursive_lock_t datatype --------------------- */
246 # if HAVE_PTHREAD_MUTEX_RECURSIVE
248 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
250 typedef pthread_mutex_t gl_recursive_lock_t;
251 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
252 STORAGECLASS pthread_mutex_t NAME;
253 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
254 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
255 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
256 # define gl_recursive_lock_initializer \
257 PTHREAD_RECURSIVE_MUTEX_INITIALIZER
259 # define gl_recursive_lock_initializer \
260 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
262 # define gl_recursive_lock_init(NAME) \
263 if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
264 # define gl_recursive_lock_lock(NAME) \
265 if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
266 # define gl_recursive_lock_unlock(NAME) \
267 if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
268 # define gl_recursive_lock_destroy(NAME) \
269 if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
275 pthread_mutex_t recmutex; /* recursive mutex */
276 pthread_mutex_t guard; /* protects the initialization */
280 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
281 STORAGECLASS gl_recursive_lock_t NAME;
282 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
283 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
284 # define gl_recursive_lock_initializer \
285 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
286 # define gl_recursive_lock_init(NAME) \
287 if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
288 # define gl_recursive_lock_lock(NAME) \
289 if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
290 # define gl_recursive_lock_unlock(NAME) \
291 if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
292 # define gl_recursive_lock_destroy(NAME) \
293 if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
294 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
295 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
296 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
297 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
303 /* Old versions of POSIX threads on Solaris did not have recursive locks.
304 We have to implement them ourselves. */
308 pthread_mutex_t mutex;
313 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
314 STORAGECLASS gl_recursive_lock_t NAME;
315 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
316 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
317 # define gl_recursive_lock_initializer \
318 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
319 # define gl_recursive_lock_init(NAME) \
320 if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
321 # define gl_recursive_lock_lock(NAME) \
322 if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
323 # define gl_recursive_lock_unlock(NAME) \
324 if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
325 # define gl_recursive_lock_destroy(NAME) \
326 if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
327 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
328 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
329 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
330 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
334 /* -------------------------- gl_once_t datatype -------------------------- */
336 typedef pthread_once_t gl_once_t;
337 # define gl_once_define(STORAGECLASS, NAME) \
338 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
339 # define gl_once(NAME, INITFUNCTION) \
342 if (pthread_in_use ()) \
344 if (pthread_once (&NAME, INITFUNCTION) != 0) \
349 if (glthread_once_singlethreaded (&NAME)) \
354 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
358 /* ========================================================================= */
362 /* Use the GNU Pth threads library. */
367 # if USE_PTH_THREADS_WEAK
369 /* Use weak references to the GNU Pth threads library. */
371 # pragma weak pth_mutex_init
372 # pragma weak pth_mutex_acquire
373 # pragma weak pth_mutex_release
374 # pragma weak pth_rwlock_init
375 # pragma weak pth_rwlock_acquire
376 # pragma weak pth_rwlock_release
377 # pragma weak pth_once
379 # pragma weak pth_cancel
380 # define pth_in_use() (pth_cancel != NULL)
384 # define pth_in_use() 1
388 /* -------------------------- gl_lock_t datatype -------------------------- */
390 typedef pth_mutex_t gl_lock_t;
391 # define gl_lock_define(STORAGECLASS, NAME) \
392 STORAGECLASS pth_mutex_t NAME;
393 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
394 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
395 # define gl_lock_initializer \
397 # define gl_lock_init(NAME) \
398 if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
399 # define gl_lock_lock(NAME) \
400 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
401 # define gl_lock_unlock(NAME) \
402 if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
403 # define gl_lock_destroy(NAME) \
406 /* ------------------------- gl_rwlock_t datatype ------------------------- */
408 typedef pth_rwlock_t gl_rwlock_t;
409 # define gl_rwlock_define(STORAGECLASS, NAME) \
410 STORAGECLASS pth_rwlock_t NAME;
411 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
412 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
413 # define gl_rwlock_initializer \
415 # define gl_rwlock_init(NAME) \
416 if (pth_in_use() && !pth_rwlock_init (&NAME)) abort ()
417 # define gl_rwlock_rdlock(NAME) \
418 if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) abort ()
419 # define gl_rwlock_wrlock(NAME) \
420 if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) abort ()
421 # define gl_rwlock_unlock(NAME) \
422 if (pth_in_use() && !pth_rwlock_release (&NAME)) abort ()
423 # define gl_rwlock_destroy(NAME) \
426 /* --------------------- gl_recursive_lock_t datatype --------------------- */
428 /* In Pth, mutexes are recursive by default. */
429 typedef pth_mutex_t gl_recursive_lock_t;
430 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
431 STORAGECLASS pth_mutex_t NAME;
432 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
433 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
434 # define gl_recursive_lock_initializer \
436 # define gl_recursive_lock_init(NAME) \
437 if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
438 # define gl_recursive_lock_lock(NAME) \
439 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
440 # define gl_recursive_lock_unlock(NAME) \
441 if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
442 # define gl_recursive_lock_destroy(NAME) \
445 /* -------------------------- gl_once_t datatype -------------------------- */
447 typedef pth_once_t gl_once_t;
448 # define gl_once_define(STORAGECLASS, NAME) \
449 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
450 # define gl_once(NAME, INITFUNCTION) \
455 void (*gl_once_temp) (void) = INITFUNCTION; \
456 if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
461 if (glthread_once_singlethreaded (&NAME)) \
466 extern void glthread_once_call (void *arg);
467 extern int glthread_once_singlethreaded (pth_once_t *once_control);
471 /* ========================================================================= */
473 #if USE_SOLARIS_THREADS
475 /* Use the old Solaris threads library. */
481 # if USE_SOLARIS_THREADS_WEAK
483 /* Use weak references to the old Solaris threads library. */
485 # pragma weak mutex_init
486 # pragma weak mutex_lock
487 # pragma weak mutex_unlock
488 # pragma weak mutex_destroy
489 # pragma weak rwlock_init
490 # pragma weak rw_rdlock
491 # pragma weak rw_wrlock
492 # pragma weak rw_unlock
493 # pragma weak rwlock_destroy
494 # pragma weak thr_self
496 # pragma weak thr_suspend
497 # define thread_in_use() (thr_suspend != NULL)
501 # define thread_in_use() 1
505 /* -------------------------- gl_lock_t datatype -------------------------- */
507 typedef mutex_t gl_lock_t;
508 # define gl_lock_define(STORAGECLASS, NAME) \
509 STORAGECLASS mutex_t NAME;
510 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
511 STORAGECLASS mutex_t NAME = gl_lock_initializer;
512 # define gl_lock_initializer \
514 # define gl_lock_init(NAME) \
515 if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
516 # define gl_lock_lock(NAME) \
517 if (thread_in_use () && mutex_lock (&NAME) != 0) abort ()
518 # define gl_lock_unlock(NAME) \
519 if (thread_in_use () && mutex_unlock (&NAME) != 0) abort ()
520 # define gl_lock_destroy(NAME) \
521 if (thread_in_use () && mutex_destroy (&NAME) != 0) abort ()
523 /* ------------------------- gl_rwlock_t datatype ------------------------- */
525 typedef rwlock_t gl_rwlock_t;
526 # define gl_rwlock_define(STORAGECLASS, NAME) \
527 STORAGECLASS rwlock_t NAME;
528 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
529 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
530 # define gl_rwlock_initializer \
532 # define gl_rwlock_init(NAME) \
533 if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
534 # define gl_rwlock_rdlock(NAME) \
535 if (thread_in_use () && rw_rdlock (&NAME) != 0) abort ()
536 # define gl_rwlock_wrlock(NAME) \
537 if (thread_in_use () && rw_wrlock (&NAME) != 0) abort ()
538 # define gl_rwlock_unlock(NAME) \
539 if (thread_in_use () && rw_unlock (&NAME) != 0) abort ()
540 # define gl_rwlock_destroy(NAME) \
541 if (thread_in_use () && rwlock_destroy (&NAME) != 0) abort ()
543 /* --------------------- gl_recursive_lock_t datatype --------------------- */
545 /* Old Solaris threads did not have recursive locks.
546 We have to implement them ourselves. */
555 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
556 STORAGECLASS gl_recursive_lock_t NAME;
557 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
558 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
559 # define gl_recursive_lock_initializer \
560 { DEFAULTMUTEX, (thread_t) 0, 0 }
561 # define gl_recursive_lock_init(NAME) \
562 if (thread_in_use ()) glthread_recursive_lock_init (&NAME)
563 # define gl_recursive_lock_lock(NAME) \
564 if (thread_in_use ()) glthread_recursive_lock_lock (&NAME)
565 # define gl_recursive_lock_unlock(NAME) \
566 if (thread_in_use ()) glthread_recursive_lock_unlock (&NAME)
567 # define gl_recursive_lock_destroy(NAME) \
568 if (thread_in_use ()) glthread_recursive_lock_destroy (&NAME)
569 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
570 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
571 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
572 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
574 /* -------------------------- gl_once_t datatype -------------------------- */
582 # define gl_once_define(STORAGECLASS, NAME) \
583 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
584 # define gl_once(NAME, INITFUNCTION) \
587 if (thread_in_use ()) \
589 glthread_once (&NAME, INITFUNCTION); \
593 if (glthread_once_singlethreaded (&NAME)) \
598 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
599 extern int glthread_once_singlethreaded (gl_once_t *once_control);
603 /* ========================================================================= */
605 #if USE_WIN32_THREADS
607 # include <windows.h>
609 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
610 Semaphore types, because
611 - we need only to synchronize inside a single process (address space),
612 not inter-process locking,
613 - we don't need to support trylock operations. (TryEnterCriticalSection
614 does not work on Windows 95/98/ME. Packages that need trylock usually
615 define their own mutex type.) */
617 /* There is no way to statically initialize a CRITICAL_SECTION. It needs
618 to be done lazily, once only. For this we need spinlocks. */
620 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
622 /* -------------------------- gl_lock_t datatype -------------------------- */
626 gl_spinlock_t guard; /* protects the initialization */
627 CRITICAL_SECTION lock;
630 # define gl_lock_define(STORAGECLASS, NAME) \
631 STORAGECLASS gl_lock_t NAME;
632 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
633 STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
634 # define gl_lock_initializer \
636 # define gl_lock_init(NAME) \
637 glthread_lock_init (&NAME)
638 # define gl_lock_lock(NAME) \
639 glthread_lock_lock (&NAME)
640 # define gl_lock_unlock(NAME) \
641 glthread_lock_unlock (&NAME)
642 # define gl_lock_destroy(NAME) \
643 glthread_lock_destroy (&NAME)
644 extern void glthread_lock_init (gl_lock_t *lock);
645 extern void glthread_lock_lock (gl_lock_t *lock);
646 extern void glthread_lock_unlock (gl_lock_t *lock);
647 extern void glthread_lock_destroy (gl_lock_t *lock);
649 /* ------------------------- gl_rwlock_t datatype ------------------------- */
651 /* It is impossible to implement read-write locks using plain locks, without
652 introducing an extra thread dedicated to managing read-write locks.
653 Therefore here we need to use the low-level Event type. */
657 HANDLE *array; /* array of waiting threads, each represented by an event */
658 unsigned int count; /* number of waiting threads */
659 unsigned int alloc; /* length of allocated array */
660 unsigned int offset; /* index of first waiting thread in array */
665 gl_spinlock_t guard; /* protects the initialization */
666 CRITICAL_SECTION lock; /* protects the remaining fields */
667 gl_waitqueue_t waiting_readers; /* waiting readers */
668 gl_waitqueue_t waiting_writers; /* waiting writers */
669 int runcount; /* number of readers running, or -1 when a writer runs */
672 # define gl_rwlock_define(STORAGECLASS, NAME) \
673 STORAGECLASS gl_rwlock_t NAME;
674 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
675 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
676 # define gl_rwlock_initializer \
678 # define gl_rwlock_init(NAME) \
679 glthread_rwlock_init (&NAME)
680 # define gl_rwlock_rdlock(NAME) \
681 glthread_rwlock_rdlock (&NAME)
682 # define gl_rwlock_wrlock(NAME) \
683 glthread_rwlock_wrlock (&NAME)
684 # define gl_rwlock_unlock(NAME) \
685 glthread_rwlock_unlock (&NAME)
686 # define gl_rwlock_destroy(NAME) \
687 glthread_rwlock_destroy (&NAME)
688 extern void glthread_rwlock_init (gl_rwlock_t *lock);
689 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
690 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
691 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
692 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
694 /* --------------------- gl_recursive_lock_t datatype --------------------- */
696 /* The Win32 documentation says that CRITICAL_SECTION already implements a
697 recursive lock. But we need not rely on it: It's easy to implement a
698 recursive lock without this assumption. */
702 gl_spinlock_t guard; /* protects the initialization */
705 CRITICAL_SECTION lock;
708 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
709 STORAGECLASS gl_recursive_lock_t NAME;
710 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
711 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
712 # define gl_recursive_lock_initializer \
714 # define gl_recursive_lock_init(NAME) \
715 glthread_recursive_lock_init (&NAME)
716 # define gl_recursive_lock_lock(NAME) \
717 glthread_recursive_lock_lock (&NAME)
718 # define gl_recursive_lock_unlock(NAME) \
719 glthread_recursive_lock_unlock (&NAME)
720 # define gl_recursive_lock_destroy(NAME) \
721 glthread_recursive_lock_destroy (&NAME)
722 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
723 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
724 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
725 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
727 /* -------------------------- gl_once_t datatype -------------------------- */
732 volatile long started;
733 CRITICAL_SECTION lock;
736 # define gl_once_define(STORAGECLASS, NAME) \
737 STORAGECLASS gl_once_t NAME = { -1, -1 };
738 # define gl_once(NAME, INITFUNCTION) \
739 glthread_once (&NAME, INITFUNCTION)
740 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
744 /* ========================================================================= */
746 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
748 /* Provide dummy implementation if threads are not supported. */
750 /* -------------------------- gl_lock_t datatype -------------------------- */
752 typedef int gl_lock_t;
753 # define gl_lock_define(STORAGECLASS, NAME)
754 # define gl_lock_define_initialized(STORAGECLASS, NAME)
755 # define gl_lock_init(NAME)
756 # define gl_lock_lock(NAME)
757 # define gl_lock_unlock(NAME)
759 /* ------------------------- gl_rwlock_t datatype ------------------------- */
761 typedef int gl_rwlock_t;
762 # define gl_rwlock_define(STORAGECLASS, NAME)
763 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
764 # define gl_rwlock_init(NAME)
765 # define gl_rwlock_rdlock(NAME)
766 # define gl_rwlock_wrlock(NAME)
767 # define gl_rwlock_unlock(NAME)
769 /* --------------------- gl_recursive_lock_t datatype --------------------- */
771 typedef int gl_recursive_lock_t;
772 # define gl_recursive_lock_define(STORAGECLASS, NAME)
773 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
774 # define gl_recursive_lock_init(NAME)
775 # define gl_recursive_lock_lock(NAME)
776 # define gl_recursive_lock_unlock(NAME)
778 /* -------------------------- gl_once_t datatype -------------------------- */
780 typedef int gl_once_t;
781 # define gl_once_define(STORAGECLASS, NAME) \
782 STORAGECLASS gl_once_t NAME = 0;
783 # define gl_once(NAME, INITFUNCTION) \