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 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. */
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 () && pthread_mutex_init (&NAME, NULL) != 0) \
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) \
396 pthread_mutex_t recmutex; /* recursive mutex */
397 pthread_mutex_t guard; /* protects the initialization */
401 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
402 STORAGECLASS gl_recursive_lock_t NAME;
403 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
404 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
405 # define gl_recursive_lock_initializer \
406 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
407 # define gl_recursive_lock_init(NAME) \
410 if (pthread_in_use ()) \
411 glthread_recursive_lock_init (&NAME); \
414 # define gl_recursive_lock_lock(NAME) \
417 if (pthread_in_use ()) \
418 glthread_recursive_lock_lock (&NAME); \
421 # define gl_recursive_lock_unlock(NAME) \
424 if (pthread_in_use ()) \
425 glthread_recursive_lock_unlock (&NAME); \
428 # define gl_recursive_lock_destroy(NAME) \
431 if (pthread_in_use ()) \
432 glthread_recursive_lock_destroy (&NAME); \
435 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
436 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
437 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
438 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
444 /* Old versions of POSIX threads on Solaris did not have recursive locks.
445 We have to implement them ourselves. */
449 pthread_mutex_t mutex;
454 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
455 STORAGECLASS gl_recursive_lock_t NAME;
456 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
457 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
458 # define gl_recursive_lock_initializer \
459 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
460 # define gl_recursive_lock_init(NAME) \
463 if (pthread_in_use ()) \
464 glthread_recursive_lock_init (&NAME); \
467 # define gl_recursive_lock_lock(NAME) \
470 if (pthread_in_use ()) \
471 glthread_recursive_lock_lock (&NAME); \
474 # define gl_recursive_lock_unlock(NAME) \
477 if (pthread_in_use ()) \
478 glthread_recursive_lock_unlock (&NAME); \
481 # define gl_recursive_lock_destroy(NAME) \
484 if (pthread_in_use ()) \
485 glthread_recursive_lock_destroy (&NAME); \
488 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
489 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
490 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
491 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
495 /* -------------------------- gl_once_t datatype -------------------------- */
497 typedef pthread_once_t gl_once_t;
498 # define gl_once_define(STORAGECLASS, NAME) \
499 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
500 # define gl_once(NAME, INITFUNCTION) \
503 if (pthread_in_use ()) \
505 if (pthread_once (&NAME, INITFUNCTION) != 0) \
510 if (glthread_once_singlethreaded (&NAME)) \
515 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
523 /* ========================================================================= */
527 /* Use the GNU Pth threads library. */
536 # if USE_PTH_THREADS_WEAK
538 /* Use weak references to the GNU Pth threads library. */
540 # pragma weak pth_mutex_init
541 # pragma weak pth_mutex_acquire
542 # pragma weak pth_mutex_release
543 # pragma weak pth_rwlock_init
544 # pragma weak pth_rwlock_acquire
545 # pragma weak pth_rwlock_release
546 # pragma weak pth_once
548 # pragma weak pth_cancel
549 # define pth_in_use() (pth_cancel != NULL)
553 # define pth_in_use() 1
557 /* -------------------------- gl_lock_t datatype -------------------------- */
559 typedef pth_mutex_t gl_lock_t;
560 # define gl_lock_define(STORAGECLASS, NAME) \
561 STORAGECLASS pth_mutex_t NAME;
562 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
563 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
564 # define gl_lock_initializer \
566 # define gl_lock_init(NAME) \
569 if (pth_in_use() && !pth_mutex_init (&NAME)) \
573 # define gl_lock_lock(NAME) \
576 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) \
580 # define gl_lock_unlock(NAME) \
583 if (pth_in_use() && !pth_mutex_release (&NAME)) \
587 # define gl_lock_destroy(NAME) \
590 /* ------------------------- gl_rwlock_t datatype ------------------------- */
592 typedef pth_rwlock_t gl_rwlock_t;
593 # define gl_rwlock_define(STORAGECLASS, NAME) \
594 STORAGECLASS pth_rwlock_t NAME;
595 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
596 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
597 # define gl_rwlock_initializer \
599 # define gl_rwlock_init(NAME) \
602 if (pth_in_use() && !pth_rwlock_init (&NAME)) \
606 # define gl_rwlock_rdlock(NAME) \
610 && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) \
614 # define gl_rwlock_wrlock(NAME) \
618 && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) \
622 # define gl_rwlock_unlock(NAME) \
625 if (pth_in_use() && !pth_rwlock_release (&NAME)) \
629 # define gl_rwlock_destroy(NAME) \
632 /* --------------------- gl_recursive_lock_t datatype --------------------- */
634 /* In Pth, mutexes are recursive by default. */
635 typedef pth_mutex_t gl_recursive_lock_t;
636 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
637 STORAGECLASS pth_mutex_t NAME;
638 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
639 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
640 # define gl_recursive_lock_initializer \
642 # define gl_recursive_lock_init(NAME) \
645 if (pth_in_use() && !pth_mutex_init (&NAME)) \
649 # define gl_recursive_lock_lock(NAME) \
652 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) \
656 # define gl_recursive_lock_unlock(NAME) \
659 if (pth_in_use() && !pth_mutex_release (&NAME)) \
663 # define gl_recursive_lock_destroy(NAME) \
666 /* -------------------------- gl_once_t datatype -------------------------- */
668 typedef pth_once_t gl_once_t;
669 # define gl_once_define(STORAGECLASS, NAME) \
670 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
671 # define gl_once(NAME, INITFUNCTION) \
676 void (*gl_once_temp) (void) = INITFUNCTION; \
677 if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
682 if (glthread_once_singlethreaded (&NAME)) \
687 extern void glthread_once_call (void *arg);
688 extern int glthread_once_singlethreaded (pth_once_t *once_control);
696 /* ========================================================================= */
698 #if USE_SOLARIS_THREADS
700 /* Use the old Solaris threads library. */
710 # if USE_SOLARIS_THREADS_WEAK
712 /* Use weak references to the old Solaris threads library. */
714 # pragma weak mutex_init
715 # pragma weak mutex_lock
716 # pragma weak mutex_unlock
717 # pragma weak mutex_destroy
718 # pragma weak rwlock_init
719 # pragma weak rw_rdlock
720 # pragma weak rw_wrlock
721 # pragma weak rw_unlock
722 # pragma weak rwlock_destroy
723 # pragma weak thr_self
725 # pragma weak thr_suspend
726 # define thread_in_use() (thr_suspend != NULL)
730 # define thread_in_use() 1
734 /* -------------------------- gl_lock_t datatype -------------------------- */
736 typedef mutex_t gl_lock_t;
737 # define gl_lock_define(STORAGECLASS, NAME) \
738 STORAGECLASS mutex_t NAME;
739 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
740 STORAGECLASS mutex_t NAME = gl_lock_initializer;
741 # define gl_lock_initializer \
743 # define gl_lock_init(NAME) \
746 if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) \
750 # define gl_lock_lock(NAME) \
753 if (thread_in_use () && mutex_lock (&NAME) != 0) \
757 # define gl_lock_unlock(NAME) \
760 if (thread_in_use () && mutex_unlock (&NAME) != 0) \
764 # define gl_lock_destroy(NAME) \
767 if (thread_in_use () && mutex_destroy (&NAME) != 0) \
772 /* ------------------------- gl_rwlock_t datatype ------------------------- */
774 typedef rwlock_t gl_rwlock_t;
775 # define gl_rwlock_define(STORAGECLASS, NAME) \
776 STORAGECLASS rwlock_t NAME;
777 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
778 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
779 # define gl_rwlock_initializer \
781 # define gl_rwlock_init(NAME) \
784 if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) \
788 # define gl_rwlock_rdlock(NAME) \
791 if (thread_in_use () && rw_rdlock (&NAME) != 0) \
795 # define gl_rwlock_wrlock(NAME) \
798 if (thread_in_use () && rw_wrlock (&NAME) != 0) \
802 # define gl_rwlock_unlock(NAME) \
805 if (thread_in_use () && rw_unlock (&NAME) != 0) \
809 # define gl_rwlock_destroy(NAME) \
812 if (thread_in_use () && rwlock_destroy (&NAME) != 0) \
817 /* --------------------- gl_recursive_lock_t datatype --------------------- */
819 /* Old Solaris threads did not have recursive locks.
820 We have to implement them ourselves. */
829 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
830 STORAGECLASS gl_recursive_lock_t NAME;
831 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
832 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
833 # define gl_recursive_lock_initializer \
834 { DEFAULTMUTEX, (thread_t) 0, 0 }
835 # define gl_recursive_lock_init(NAME) \
838 if (thread_in_use ()) \
839 glthread_recursive_lock_init (&NAME); \
842 # define gl_recursive_lock_lock(NAME) \
845 if (thread_in_use ()) \
846 glthread_recursive_lock_lock (&NAME); \
849 # define gl_recursive_lock_unlock(NAME) \
852 if (thread_in_use ()) \
853 glthread_recursive_lock_unlock (&NAME); \
856 # define gl_recursive_lock_destroy(NAME) \
859 if (thread_in_use ()) \
860 glthread_recursive_lock_destroy (&NAME); \
863 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
864 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
865 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
866 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
868 /* -------------------------- gl_once_t datatype -------------------------- */
876 # define gl_once_define(STORAGECLASS, NAME) \
877 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
878 # define gl_once(NAME, INITFUNCTION) \
881 if (thread_in_use ()) \
883 glthread_once (&NAME, INITFUNCTION); \
887 if (glthread_once_singlethreaded (&NAME)) \
892 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
893 extern int glthread_once_singlethreaded (gl_once_t *once_control);
901 /* ========================================================================= */
903 #if USE_WIN32_THREADS
905 # include <windows.h>
911 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
912 Semaphore types, because
913 - we need only to synchronize inside a single process (address space),
914 not inter-process locking,
915 - we don't need to support trylock operations. (TryEnterCriticalSection
916 does not work on Windows 95/98/ME. Packages that need trylock usually
917 define their own mutex type.) */
919 /* There is no way to statically initialize a CRITICAL_SECTION. It needs
920 to be done lazily, once only. For this we need spinlocks. */
922 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
924 /* -------------------------- gl_lock_t datatype -------------------------- */
928 gl_spinlock_t guard; /* protects the initialization */
929 CRITICAL_SECTION lock;
932 # define gl_lock_define(STORAGECLASS, NAME) \
933 STORAGECLASS gl_lock_t NAME;
934 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
935 STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
936 # define gl_lock_initializer \
938 # define gl_lock_init(NAME) \
939 glthread_lock_init (&NAME)
940 # define gl_lock_lock(NAME) \
941 glthread_lock_lock (&NAME)
942 # define gl_lock_unlock(NAME) \
943 glthread_lock_unlock (&NAME)
944 # define gl_lock_destroy(NAME) \
945 glthread_lock_destroy (&NAME)
946 extern void glthread_lock_init (gl_lock_t *lock);
947 extern void glthread_lock_lock (gl_lock_t *lock);
948 extern void glthread_lock_unlock (gl_lock_t *lock);
949 extern void glthread_lock_destroy (gl_lock_t *lock);
951 /* ------------------------- gl_rwlock_t datatype ------------------------- */
953 /* It is impossible to implement read-write locks using plain locks, without
954 introducing an extra thread dedicated to managing read-write locks.
955 Therefore here we need to use the low-level Event type. */
959 HANDLE *array; /* array of waiting threads, each represented by an event */
960 unsigned int count; /* number of waiting threads */
961 unsigned int alloc; /* length of allocated array */
962 unsigned int offset; /* index of first waiting thread in array */
967 gl_spinlock_t guard; /* protects the initialization */
968 CRITICAL_SECTION lock; /* protects the remaining fields */
969 gl_waitqueue_t waiting_readers; /* waiting readers */
970 gl_waitqueue_t waiting_writers; /* waiting writers */
971 int runcount; /* number of readers running, or -1 when a writer runs */
974 # define gl_rwlock_define(STORAGECLASS, NAME) \
975 STORAGECLASS gl_rwlock_t NAME;
976 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
977 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
978 # define gl_rwlock_initializer \
980 # define gl_rwlock_init(NAME) \
981 glthread_rwlock_init (&NAME)
982 # define gl_rwlock_rdlock(NAME) \
983 glthread_rwlock_rdlock (&NAME)
984 # define gl_rwlock_wrlock(NAME) \
985 glthread_rwlock_wrlock (&NAME)
986 # define gl_rwlock_unlock(NAME) \
987 glthread_rwlock_unlock (&NAME)
988 # define gl_rwlock_destroy(NAME) \
989 glthread_rwlock_destroy (&NAME)
990 extern void glthread_rwlock_init (gl_rwlock_t *lock);
991 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
992 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
993 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
994 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
996 /* --------------------- gl_recursive_lock_t datatype --------------------- */
998 /* The Win32 documentation says that CRITICAL_SECTION already implements a
999 recursive lock. But we need not rely on it: It's easy to implement a
1000 recursive lock without this assumption. */
1004 gl_spinlock_t guard; /* protects the initialization */
1006 unsigned long depth;
1007 CRITICAL_SECTION lock;
1009 gl_recursive_lock_t;
1010 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
1011 STORAGECLASS gl_recursive_lock_t NAME;
1012 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
1013 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
1014 # define gl_recursive_lock_initializer \
1016 # define gl_recursive_lock_init(NAME) \
1017 glthread_recursive_lock_init (&NAME)
1018 # define gl_recursive_lock_lock(NAME) \
1019 glthread_recursive_lock_lock (&NAME)
1020 # define gl_recursive_lock_unlock(NAME) \
1021 glthread_recursive_lock_unlock (&NAME)
1022 # define gl_recursive_lock_destroy(NAME) \
1023 glthread_recursive_lock_destroy (&NAME)
1024 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
1025 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
1026 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
1027 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
1029 /* -------------------------- gl_once_t datatype -------------------------- */
1033 volatile int inited;
1034 volatile long started;
1035 CRITICAL_SECTION lock;
1038 # define gl_once_define(STORAGECLASS, NAME) \
1039 STORAGECLASS gl_once_t NAME = { -1, -1 };
1040 # define gl_once(NAME, INITFUNCTION) \
1041 glthread_once (&NAME, INITFUNCTION)
1042 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
1050 /* ========================================================================= */
1052 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
1054 /* Provide dummy implementation if threads are not supported. */
1056 /* -------------------------- gl_lock_t datatype -------------------------- */
1058 typedef int gl_lock_t;
1059 # define gl_lock_define(STORAGECLASS, NAME)
1060 # define gl_lock_define_initialized(STORAGECLASS, NAME)
1061 # define gl_lock_init(NAME)
1062 # define gl_lock_lock(NAME)
1063 # define gl_lock_unlock(NAME)
1065 /* ------------------------- gl_rwlock_t datatype ------------------------- */
1067 typedef int gl_rwlock_t;
1068 # define gl_rwlock_define(STORAGECLASS, NAME)
1069 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
1070 # define gl_rwlock_init(NAME)
1071 # define gl_rwlock_rdlock(NAME)
1072 # define gl_rwlock_wrlock(NAME)
1073 # define gl_rwlock_unlock(NAME)
1075 /* --------------------- gl_recursive_lock_t datatype --------------------- */
1077 typedef int gl_recursive_lock_t;
1078 # define gl_recursive_lock_define(STORAGECLASS, NAME)
1079 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
1080 # define gl_recursive_lock_init(NAME)
1081 # define gl_recursive_lock_lock(NAME)
1082 # define gl_recursive_lock_unlock(NAME)
1084 /* -------------------------- gl_once_t datatype -------------------------- */
1086 typedef int gl_once_t;
1087 # define gl_once_define(STORAGECLASS, NAME) \
1088 STORAGECLASS gl_once_t NAME = 0;
1089 # define gl_once(NAME, INITFUNCTION) \
1102 /* ========================================================================= */
1104 #endif /* _LOCK_H */