1 /* Locking in multithreaded situations.
2 Copyright (C) 2005-2007 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);
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. */
77 # if PTHREAD_IN_USE_DETECTION_HARD
79 /* The pthread_in_use() detection needs to be done at runtime. */
80 # define pthread_in_use() \
82 extern int glthread_in_use (void);
86 # if USE_POSIX_THREADS_WEAK
88 /* Use weak references to the POSIX threads library. */
90 /* Weak references avoid dragging in external libraries if the other parts
91 of the program don't use them. Here we use them, because we don't want
92 every program that uses libintl to depend on libpthread. This assumes
93 that libpthread would not be loaded after libintl; i.e. if libintl is
94 loaded first, by an executable that does not depend on libpthread, and
95 then a module is dynamically loaded that depends on libpthread, libintl
96 will not be multithread-safe. */
98 /* The way to test at runtime whether libpthread is present is to test
99 whether a function pointer's value, such as &pthread_mutex_init, is
100 non-NULL. However, some versions of GCC have a bug through which, in
101 PIC mode, &foo != NULL always evaluates to true if there is a direct
102 call to foo(...) in the same function. To avoid this, we test the
103 address of a function in libpthread that we don't use. */
105 # pragma weak pthread_mutex_init
106 # pragma weak pthread_mutex_lock
107 # pragma weak pthread_mutex_unlock
108 # pragma weak pthread_mutex_destroy
109 # pragma weak pthread_rwlock_init
110 # pragma weak pthread_rwlock_rdlock
111 # pragma weak pthread_rwlock_wrlock
112 # pragma weak pthread_rwlock_unlock
113 # pragma weak pthread_rwlock_destroy
114 # pragma weak pthread_once
115 # pragma weak pthread_cond_init
116 # pragma weak pthread_cond_wait
117 # pragma weak pthread_cond_signal
118 # pragma weak pthread_cond_broadcast
119 # pragma weak pthread_cond_destroy
120 # pragma weak pthread_mutexattr_init
121 # pragma weak pthread_mutexattr_settype
122 # pragma weak pthread_mutexattr_destroy
123 # ifndef pthread_self
124 # pragma weak pthread_self
127 # if !PTHREAD_IN_USE_DETECTION_HARD
128 # pragma weak pthread_cancel
129 # define pthread_in_use() (pthread_cancel != NULL)
134 # if !PTHREAD_IN_USE_DETECTION_HARD
135 # define pthread_in_use() 1
140 /* -------------------------- gl_lock_t datatype -------------------------- */
142 typedef pthread_mutex_t gl_lock_t;
143 # define gl_lock_define(STORAGECLASS, NAME) \
144 STORAGECLASS pthread_mutex_t NAME;
145 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
146 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
147 # define gl_lock_initializer \
148 PTHREAD_MUTEX_INITIALIZER
149 # define gl_lock_init(NAME) \
152 if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) \
156 # define gl_lock_lock(NAME) \
159 if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) \
163 # define gl_lock_unlock(NAME) \
166 if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) \
170 # define gl_lock_destroy(NAME) \
173 if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 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 gl_rwlock_init(NAME) \
194 if (pthread_in_use () && pthread_rwlock_init (&NAME, NULL) != 0) \
198 # define gl_rwlock_rdlock(NAME) \
201 if (pthread_in_use () && pthread_rwlock_rdlock (&NAME) != 0) \
205 # define gl_rwlock_wrlock(NAME) \
208 if (pthread_in_use () && pthread_rwlock_wrlock (&NAME) != 0) \
212 # define gl_rwlock_unlock(NAME) \
215 if (pthread_in_use () && pthread_rwlock_unlock (&NAME) != 0) \
219 # define gl_rwlock_destroy(NAME) \
222 if (pthread_in_use () && pthread_rwlock_destroy (&NAME) != 0) \
232 pthread_mutex_t guard; /* protects the initialization */
233 pthread_rwlock_t rwlock; /* read-write lock */
236 # define gl_rwlock_define(STORAGECLASS, NAME) \
237 STORAGECLASS gl_rwlock_t NAME;
238 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
239 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
240 # define gl_rwlock_initializer \
241 { 0, PTHREAD_MUTEX_INITIALIZER }
242 # define gl_rwlock_init(NAME) \
245 if (pthread_in_use ()) \
246 glthread_rwlock_init (&NAME); \
249 # define gl_rwlock_rdlock(NAME) \
252 if (pthread_in_use ()) \
253 glthread_rwlock_rdlock (&NAME); \
256 # define gl_rwlock_wrlock(NAME) \
259 if (pthread_in_use ()) \
260 glthread_rwlock_wrlock (&NAME); \
263 # define gl_rwlock_unlock(NAME) \
266 if (pthread_in_use ()) \
267 glthread_rwlock_unlock (&NAME); \
270 # define gl_rwlock_destroy(NAME) \
273 if (pthread_in_use ()) \
274 glthread_rwlock_destroy (&NAME); \
277 extern void glthread_rwlock_init (gl_rwlock_t *lock);
278 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
279 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
280 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
281 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
289 pthread_mutex_t lock; /* protects the remaining fields */
290 pthread_cond_t waiting_readers; /* waiting readers */
291 pthread_cond_t waiting_writers; /* waiting writers */
292 unsigned int waiting_writers_count; /* number of waiting writers */
293 int runcount; /* number of readers running, or -1 when a writer runs */
296 # define gl_rwlock_define(STORAGECLASS, NAME) \
297 STORAGECLASS gl_rwlock_t NAME;
298 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
299 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
300 # define gl_rwlock_initializer \
301 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
302 # define gl_rwlock_init(NAME) \
305 if (pthread_in_use ()) \
306 glthread_rwlock_init (&NAME); \
309 # define gl_rwlock_rdlock(NAME) \
312 if (pthread_in_use ()) \
313 glthread_rwlock_rdlock (&NAME); \
316 # define gl_rwlock_wrlock(NAME) \
319 if (pthread_in_use ()) \
320 glthread_rwlock_wrlock (&NAME); \
323 # define gl_rwlock_unlock(NAME) \
326 if (pthread_in_use ()) \
327 glthread_rwlock_unlock (&NAME); \
330 # define gl_rwlock_destroy(NAME) \
333 if (pthread_in_use ()) \
334 glthread_rwlock_destroy (&NAME); \
337 extern void glthread_rwlock_init (gl_rwlock_t *lock);
338 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
339 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
340 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
341 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
345 /* --------------------- gl_recursive_lock_t datatype --------------------- */
347 # if HAVE_PTHREAD_MUTEX_RECURSIVE
349 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
351 typedef pthread_mutex_t gl_recursive_lock_t;
352 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
353 STORAGECLASS pthread_mutex_t NAME;
354 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
355 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
356 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
357 # define gl_recursive_lock_initializer \
358 PTHREAD_RECURSIVE_MUTEX_INITIALIZER
360 # define gl_recursive_lock_initializer \
361 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
363 # define gl_recursive_lock_init(NAME) \
366 if (pthread_in_use ()) \
367 glthread_recursive_lock_init (&NAME); \
370 # define gl_recursive_lock_lock(NAME) \
373 if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) \
377 # define gl_recursive_lock_unlock(NAME) \
380 if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) \
384 # define gl_recursive_lock_destroy(NAME) \
387 if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) \
391 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
397 pthread_mutex_t recmutex; /* recursive mutex */
398 pthread_mutex_t guard; /* protects the initialization */
402 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
403 STORAGECLASS gl_recursive_lock_t NAME;
404 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
405 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
406 # define gl_recursive_lock_initializer \
407 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
408 # define gl_recursive_lock_init(NAME) \
411 if (pthread_in_use ()) \
412 glthread_recursive_lock_init (&NAME); \
415 # define gl_recursive_lock_lock(NAME) \
418 if (pthread_in_use ()) \
419 glthread_recursive_lock_lock (&NAME); \
422 # define gl_recursive_lock_unlock(NAME) \
425 if (pthread_in_use ()) \
426 glthread_recursive_lock_unlock (&NAME); \
429 # define gl_recursive_lock_destroy(NAME) \
432 if (pthread_in_use ()) \
433 glthread_recursive_lock_destroy (&NAME); \
436 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
437 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
438 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
439 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
445 /* Old versions of POSIX threads on Solaris did not have recursive locks.
446 We have to implement them ourselves. */
450 pthread_mutex_t mutex;
455 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
456 STORAGECLASS gl_recursive_lock_t NAME;
457 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
458 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
459 # define gl_recursive_lock_initializer \
460 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
461 # define gl_recursive_lock_init(NAME) \
464 if (pthread_in_use ()) \
465 glthread_recursive_lock_init (&NAME); \
468 # define gl_recursive_lock_lock(NAME) \
471 if (pthread_in_use ()) \
472 glthread_recursive_lock_lock (&NAME); \
475 # define gl_recursive_lock_unlock(NAME) \
478 if (pthread_in_use ()) \
479 glthread_recursive_lock_unlock (&NAME); \
482 # define gl_recursive_lock_destroy(NAME) \
485 if (pthread_in_use ()) \
486 glthread_recursive_lock_destroy (&NAME); \
489 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
490 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
491 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
492 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
496 /* -------------------------- gl_once_t datatype -------------------------- */
498 typedef pthread_once_t gl_once_t;
499 # define gl_once_define(STORAGECLASS, NAME) \
500 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
501 # define gl_once(NAME, INITFUNCTION) \
504 if (pthread_in_use ()) \
506 if (pthread_once (&NAME, INITFUNCTION) != 0) \
511 if (glthread_once_singlethreaded (&NAME)) \
516 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
524 /* ========================================================================= */
528 /* Use the GNU Pth threads library. */
537 # if USE_PTH_THREADS_WEAK
539 /* Use weak references to the GNU Pth threads library. */
541 # pragma weak pth_mutex_init
542 # pragma weak pth_mutex_acquire
543 # pragma weak pth_mutex_release
544 # pragma weak pth_rwlock_init
545 # pragma weak pth_rwlock_acquire
546 # pragma weak pth_rwlock_release
547 # pragma weak pth_once
549 # pragma weak pth_cancel
550 # define pth_in_use() (pth_cancel != NULL)
554 # define pth_in_use() 1
558 /* -------------------------- gl_lock_t datatype -------------------------- */
560 typedef pth_mutex_t gl_lock_t;
561 # define gl_lock_define(STORAGECLASS, NAME) \
562 STORAGECLASS pth_mutex_t NAME;
563 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
564 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
565 # define gl_lock_initializer \
567 # define gl_lock_init(NAME) \
570 if (pth_in_use() && !pth_mutex_init (&NAME)) \
574 # define gl_lock_lock(NAME) \
577 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) \
581 # define gl_lock_unlock(NAME) \
584 if (pth_in_use() && !pth_mutex_release (&NAME)) \
588 # define gl_lock_destroy(NAME) \
591 /* ------------------------- gl_rwlock_t datatype ------------------------- */
593 typedef pth_rwlock_t gl_rwlock_t;
594 # define gl_rwlock_define(STORAGECLASS, NAME) \
595 STORAGECLASS pth_rwlock_t NAME;
596 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
597 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
598 # define gl_rwlock_initializer \
600 # define gl_rwlock_init(NAME) \
603 if (pth_in_use() && !pth_rwlock_init (&NAME)) \
607 # define gl_rwlock_rdlock(NAME) \
611 && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) \
615 # define gl_rwlock_wrlock(NAME) \
619 && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) \
623 # define gl_rwlock_unlock(NAME) \
626 if (pth_in_use() && !pth_rwlock_release (&NAME)) \
630 # define gl_rwlock_destroy(NAME) \
633 /* --------------------- gl_recursive_lock_t datatype --------------------- */
635 /* In Pth, mutexes are recursive by default. */
636 typedef pth_mutex_t gl_recursive_lock_t;
637 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
638 STORAGECLASS pth_mutex_t NAME;
639 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
640 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
641 # define gl_recursive_lock_initializer \
643 # define gl_recursive_lock_init(NAME) \
646 if (pth_in_use() && !pth_mutex_init (&NAME)) \
650 # define gl_recursive_lock_lock(NAME) \
653 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) \
657 # define gl_recursive_lock_unlock(NAME) \
660 if (pth_in_use() && !pth_mutex_release (&NAME)) \
664 # define gl_recursive_lock_destroy(NAME) \
667 /* -------------------------- gl_once_t datatype -------------------------- */
669 typedef pth_once_t gl_once_t;
670 # define gl_once_define(STORAGECLASS, NAME) \
671 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
672 # define gl_once(NAME, INITFUNCTION) \
677 void (*gl_once_temp) (void) = INITFUNCTION; \
678 if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
683 if (glthread_once_singlethreaded (&NAME)) \
688 extern void glthread_once_call (void *arg);
689 extern int glthread_once_singlethreaded (pth_once_t *once_control);
697 /* ========================================================================= */
699 #if USE_SOLARIS_THREADS
701 /* Use the old Solaris threads library. */
711 # if USE_SOLARIS_THREADS_WEAK
713 /* Use weak references to the old Solaris threads library. */
715 # pragma weak mutex_init
716 # pragma weak mutex_lock
717 # pragma weak mutex_unlock
718 # pragma weak mutex_destroy
719 # pragma weak rwlock_init
720 # pragma weak rw_rdlock
721 # pragma weak rw_wrlock
722 # pragma weak rw_unlock
723 # pragma weak rwlock_destroy
724 # pragma weak thr_self
726 # pragma weak thr_suspend
727 # define thread_in_use() (thr_suspend != NULL)
731 # define thread_in_use() 1
735 /* -------------------------- gl_lock_t datatype -------------------------- */
737 typedef mutex_t gl_lock_t;
738 # define gl_lock_define(STORAGECLASS, NAME) \
739 STORAGECLASS mutex_t NAME;
740 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
741 STORAGECLASS mutex_t NAME = gl_lock_initializer;
742 # define gl_lock_initializer \
744 # define gl_lock_init(NAME) \
747 if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) \
751 # define gl_lock_lock(NAME) \
754 if (thread_in_use () && mutex_lock (&NAME) != 0) \
758 # define gl_lock_unlock(NAME) \
761 if (thread_in_use () && mutex_unlock (&NAME) != 0) \
765 # define gl_lock_destroy(NAME) \
768 if (thread_in_use () && mutex_destroy (&NAME) != 0) \
773 /* ------------------------- gl_rwlock_t datatype ------------------------- */
775 typedef rwlock_t gl_rwlock_t;
776 # define gl_rwlock_define(STORAGECLASS, NAME) \
777 STORAGECLASS rwlock_t NAME;
778 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
779 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
780 # define gl_rwlock_initializer \
782 # define gl_rwlock_init(NAME) \
785 if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) \
789 # define gl_rwlock_rdlock(NAME) \
792 if (thread_in_use () && rw_rdlock (&NAME) != 0) \
796 # define gl_rwlock_wrlock(NAME) \
799 if (thread_in_use () && rw_wrlock (&NAME) != 0) \
803 # define gl_rwlock_unlock(NAME) \
806 if (thread_in_use () && rw_unlock (&NAME) != 0) \
810 # define gl_rwlock_destroy(NAME) \
813 if (thread_in_use () && rwlock_destroy (&NAME) != 0) \
818 /* --------------------- gl_recursive_lock_t datatype --------------------- */
820 /* Old Solaris threads did not have recursive locks.
821 We have to implement them ourselves. */
830 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
831 STORAGECLASS gl_recursive_lock_t NAME;
832 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
833 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
834 # define gl_recursive_lock_initializer \
835 { DEFAULTMUTEX, (thread_t) 0, 0 }
836 # define gl_recursive_lock_init(NAME) \
839 if (thread_in_use ()) \
840 glthread_recursive_lock_init (&NAME); \
843 # define gl_recursive_lock_lock(NAME) \
846 if (thread_in_use ()) \
847 glthread_recursive_lock_lock (&NAME); \
850 # define gl_recursive_lock_unlock(NAME) \
853 if (thread_in_use ()) \
854 glthread_recursive_lock_unlock (&NAME); \
857 # define gl_recursive_lock_destroy(NAME) \
860 if (thread_in_use ()) \
861 glthread_recursive_lock_destroy (&NAME); \
864 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
865 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
866 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
867 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
869 /* -------------------------- gl_once_t datatype -------------------------- */
877 # define gl_once_define(STORAGECLASS, NAME) \
878 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
879 # define gl_once(NAME, INITFUNCTION) \
882 if (thread_in_use ()) \
884 glthread_once (&NAME, INITFUNCTION); \
888 if (glthread_once_singlethreaded (&NAME)) \
893 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
894 extern int glthread_once_singlethreaded (gl_once_t *once_control);
902 /* ========================================================================= */
904 #if USE_WIN32_THREADS
906 # include <windows.h>
912 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
913 Semaphore types, because
914 - we need only to synchronize inside a single process (address space),
915 not inter-process locking,
916 - we don't need to support trylock operations. (TryEnterCriticalSection
917 does not work on Windows 95/98/ME. Packages that need trylock usually
918 define their own mutex type.) */
920 /* There is no way to statically initialize a CRITICAL_SECTION. It needs
921 to be done lazily, once only. For this we need spinlocks. */
923 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
925 /* -------------------------- gl_lock_t datatype -------------------------- */
929 gl_spinlock_t guard; /* protects the initialization */
930 CRITICAL_SECTION lock;
933 # define gl_lock_define(STORAGECLASS, NAME) \
934 STORAGECLASS gl_lock_t NAME;
935 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
936 STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
937 # define gl_lock_initializer \
939 # define gl_lock_init(NAME) \
940 glthread_lock_init (&NAME)
941 # define gl_lock_lock(NAME) \
942 glthread_lock_lock (&NAME)
943 # define gl_lock_unlock(NAME) \
944 glthread_lock_unlock (&NAME)
945 # define gl_lock_destroy(NAME) \
946 glthread_lock_destroy (&NAME)
947 extern void glthread_lock_init (gl_lock_t *lock);
948 extern void glthread_lock_lock (gl_lock_t *lock);
949 extern void glthread_lock_unlock (gl_lock_t *lock);
950 extern void glthread_lock_destroy (gl_lock_t *lock);
952 /* ------------------------- gl_rwlock_t datatype ------------------------- */
954 /* It is impossible to implement read-write locks using plain locks, without
955 introducing an extra thread dedicated to managing read-write locks.
956 Therefore here we need to use the low-level Event type. */
960 HANDLE *array; /* array of waiting threads, each represented by an event */
961 unsigned int count; /* number of waiting threads */
962 unsigned int alloc; /* length of allocated array */
963 unsigned int offset; /* index of first waiting thread in array */
968 gl_spinlock_t guard; /* protects the initialization */
969 CRITICAL_SECTION lock; /* protects the remaining fields */
970 gl_waitqueue_t waiting_readers; /* waiting readers */
971 gl_waitqueue_t waiting_writers; /* waiting writers */
972 int runcount; /* number of readers running, or -1 when a writer runs */
975 # define gl_rwlock_define(STORAGECLASS, NAME) \
976 STORAGECLASS gl_rwlock_t NAME;
977 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
978 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
979 # define gl_rwlock_initializer \
981 # define gl_rwlock_init(NAME) \
982 glthread_rwlock_init (&NAME)
983 # define gl_rwlock_rdlock(NAME) \
984 glthread_rwlock_rdlock (&NAME)
985 # define gl_rwlock_wrlock(NAME) \
986 glthread_rwlock_wrlock (&NAME)
987 # define gl_rwlock_unlock(NAME) \
988 glthread_rwlock_unlock (&NAME)
989 # define gl_rwlock_destroy(NAME) \
990 glthread_rwlock_destroy (&NAME)
991 extern void glthread_rwlock_init (gl_rwlock_t *lock);
992 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
993 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
994 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
995 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
997 /* --------------------- gl_recursive_lock_t datatype --------------------- */
999 /* The Win32 documentation says that CRITICAL_SECTION already implements a
1000 recursive lock. But we need not rely on it: It's easy to implement a
1001 recursive lock without this assumption. */
1005 gl_spinlock_t guard; /* protects the initialization */
1007 unsigned long depth;
1008 CRITICAL_SECTION lock;
1010 gl_recursive_lock_t;
1011 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
1012 STORAGECLASS gl_recursive_lock_t NAME;
1013 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
1014 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
1015 # define gl_recursive_lock_initializer \
1017 # define gl_recursive_lock_init(NAME) \
1018 glthread_recursive_lock_init (&NAME)
1019 # define gl_recursive_lock_lock(NAME) \
1020 glthread_recursive_lock_lock (&NAME)
1021 # define gl_recursive_lock_unlock(NAME) \
1022 glthread_recursive_lock_unlock (&NAME)
1023 # define gl_recursive_lock_destroy(NAME) \
1024 glthread_recursive_lock_destroy (&NAME)
1025 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
1026 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
1027 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
1028 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
1030 /* -------------------------- gl_once_t datatype -------------------------- */
1034 volatile int inited;
1035 volatile long started;
1036 CRITICAL_SECTION lock;
1039 # define gl_once_define(STORAGECLASS, NAME) \
1040 STORAGECLASS gl_once_t NAME = { -1, -1 };
1041 # define gl_once(NAME, INITFUNCTION) \
1042 glthread_once (&NAME, INITFUNCTION)
1043 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
1051 /* ========================================================================= */
1053 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
1055 /* Provide dummy implementation if threads are not supported. */
1057 /* -------------------------- gl_lock_t datatype -------------------------- */
1059 typedef int gl_lock_t;
1060 # define gl_lock_define(STORAGECLASS, NAME)
1061 # define gl_lock_define_initialized(STORAGECLASS, NAME)
1062 # define gl_lock_init(NAME)
1063 # define gl_lock_lock(NAME)
1064 # define gl_lock_unlock(NAME)
1066 /* ------------------------- gl_rwlock_t datatype ------------------------- */
1068 typedef int gl_rwlock_t;
1069 # define gl_rwlock_define(STORAGECLASS, NAME)
1070 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
1071 # define gl_rwlock_init(NAME)
1072 # define gl_rwlock_rdlock(NAME)
1073 # define gl_rwlock_wrlock(NAME)
1074 # define gl_rwlock_unlock(NAME)
1076 /* --------------------- gl_recursive_lock_t datatype --------------------- */
1078 typedef int gl_recursive_lock_t;
1079 # define gl_recursive_lock_define(STORAGECLASS, NAME)
1080 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
1081 # define gl_recursive_lock_init(NAME)
1082 # define gl_recursive_lock_lock(NAME)
1083 # define gl_recursive_lock_unlock(NAME)
1085 /* -------------------------- gl_once_t datatype -------------------------- */
1087 typedef int gl_once_t;
1088 # define gl_once_define(STORAGECLASS, NAME) \
1089 STORAGECLASS gl_once_t NAME = 0;
1090 # define gl_once(NAME, INITFUNCTION) \
1103 /* ========================================================================= */
1105 #endif /* _LOCK_H */