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 = PTHREAD_MUTEX_INITIALIZER;
141 # define gl_lock_init(NAME) \
142 if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
143 # define gl_lock_lock(NAME) \
144 if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
145 # define gl_lock_unlock(NAME) \
146 if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
147 # define gl_lock_destroy(NAME) \
148 if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
150 /* ------------------------- gl_rwlock_t datatype ------------------------- */
152 # if HAVE_PTHREAD_RWLOCK
154 # ifdef PTHREAD_RWLOCK_INITIALIZER
156 typedef pthread_rwlock_t gl_rwlock_t;
157 # define gl_rwlock_define(STORAGECLASS, NAME) \
158 STORAGECLASS pthread_rwlock_t NAME;
159 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
160 STORAGECLASS pthread_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER;
161 # define gl_rwlock_init(NAME) \
162 if (pthread_in_use () && pthread_rwlock_init (&NAME, NULL) != 0) abort ()
163 # define gl_rwlock_rdlock(NAME) \
164 if (pthread_in_use () && pthread_rwlock_rdlock (&NAME) != 0) abort ()
165 # define gl_rwlock_wrlock(NAME) \
166 if (pthread_in_use () && pthread_rwlock_wrlock (&NAME) != 0) abort ()
167 # define gl_rwlock_unlock(NAME) \
168 if (pthread_in_use () && pthread_rwlock_unlock (&NAME) != 0) abort ()
169 # define gl_rwlock_destroy(NAME) \
170 if (pthread_in_use () && pthread_rwlock_destroy (&NAME) != 0) abort ()
177 pthread_mutex_t guard; /* protects the initialization */
178 pthread_rwlock_t rwlock; /* read-write lock */
181 # define gl_rwlock_define(STORAGECLASS, NAME) \
182 STORAGECLASS gl_rwlock_t NAME;
183 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
184 STORAGECLASS gl_rwlock_t NAME = { 0, PTHREAD_MUTEX_INITIALIZER };
185 # define gl_rwlock_init(NAME) \
186 if (pthread_in_use ()) glthread_rwlock_init (&NAME)
187 # define gl_rwlock_rdlock(NAME) \
188 if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
189 # define gl_rwlock_wrlock(NAME) \
190 if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
191 # define gl_rwlock_unlock(NAME) \
192 if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
193 # define gl_rwlock_destroy(NAME) \
194 if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
195 extern void glthread_rwlock_init (gl_rwlock_t *lock);
196 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
197 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
198 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
199 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
207 pthread_mutex_t lock; /* protects the remaining fields */
208 pthread_cond_t waiting_readers; /* waiting readers */
209 pthread_cond_t waiting_writers; /* waiting writers */
210 unsigned int waiting_writers_count; /* number of waiting writers */
211 int runcount; /* number of readers running, or -1 when a writer runs */
214 # define gl_rwlock_define(STORAGECLASS, NAME) \
215 STORAGECLASS gl_rwlock_t NAME;
216 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
217 STORAGECLASS gl_rwlock_t NAME = \
218 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 };
219 # define gl_rwlock_init(NAME) \
220 if (pthread_in_use ()) glthread_rwlock_init (&NAME)
221 # define gl_rwlock_rdlock(NAME) \
222 if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
223 # define gl_rwlock_wrlock(NAME) \
224 if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
225 # define gl_rwlock_unlock(NAME) \
226 if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
227 # define gl_rwlock_destroy(NAME) \
228 if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
229 extern void glthread_rwlock_init (gl_rwlock_t *lock);
230 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
231 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
232 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
233 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
237 /* --------------------- gl_recursive_lock_t datatype --------------------- */
239 # if HAVE_PTHREAD_MUTEX_RECURSIVE
241 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
243 typedef pthread_mutex_t gl_recursive_lock_t;
244 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
245 STORAGECLASS pthread_mutex_t NAME;
246 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
247 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
248 STORAGECLASS pthread_mutex_t NAME = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
250 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
251 STORAGECLASS pthread_mutex_t NAME = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
253 # define gl_recursive_lock_init(NAME) \
254 if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
255 # define gl_recursive_lock_lock(NAME) \
256 if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
257 # define gl_recursive_lock_unlock(NAME) \
258 if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
259 # define gl_recursive_lock_destroy(NAME) \
260 if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
266 pthread_mutex_t recmutex; /* recursive mutex */
267 pthread_mutex_t guard; /* protects the initialization */
271 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
272 STORAGECLASS gl_recursive_lock_t NAME;
273 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
274 STORAGECLASS gl_recursive_lock_t NAME = \
275 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 };
276 # define gl_recursive_lock_init(NAME) \
277 if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
278 # define gl_recursive_lock_lock(NAME) \
279 if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
280 # define gl_recursive_lock_unlock(NAME) \
281 if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
282 # define gl_recursive_lock_destroy(NAME) \
283 if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
284 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
285 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
286 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
287 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
293 /* Old versions of POSIX threads on Solaris did not have recursive locks.
294 We have to implement them ourselves. */
298 pthread_mutex_t mutex;
303 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
304 STORAGECLASS gl_recursive_lock_t NAME;
305 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
306 STORAGECLASS gl_recursive_lock_t NAME = \
307 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 };
308 # define gl_recursive_lock_init(NAME) \
309 if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
310 # define gl_recursive_lock_lock(NAME) \
311 if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
312 # define gl_recursive_lock_unlock(NAME) \
313 if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
314 # define gl_recursive_lock_destroy(NAME) \
315 if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
316 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
317 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
318 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
319 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
323 /* -------------------------- gl_once_t datatype -------------------------- */
325 typedef pthread_once_t gl_once_t;
326 # define gl_once_define(STORAGECLASS, NAME) \
327 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
328 # define gl_once(NAME, INITFUNCTION) \
331 if (pthread_in_use ()) \
333 if (pthread_once (&NAME, INITFUNCTION) != 0) \
338 if (glthread_once_singlethreaded (&NAME)) \
343 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
347 /* ========================================================================= */
351 /* Use the GNU Pth threads library. */
356 # if USE_PTH_THREADS_WEAK
358 /* Use weak references to the GNU Pth threads library. */
360 # pragma weak pth_mutex_init
361 # pragma weak pth_mutex_acquire
362 # pragma weak pth_mutex_release
363 # pragma weak pth_rwlock_init
364 # pragma weak pth_rwlock_acquire
365 # pragma weak pth_rwlock_release
366 # pragma weak pth_once
368 # pragma weak pth_cancel
369 # define pth_in_use() (pth_cancel != NULL)
373 # define pth_in_use() 1
377 /* -------------------------- gl_lock_t datatype -------------------------- */
379 typedef pth_mutex_t gl_lock_t;
380 # define gl_lock_define(STORAGECLASS, NAME) \
381 STORAGECLASS pth_mutex_t NAME;
382 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
383 STORAGECLASS pth_mutex_t NAME = PTH_MUTEX_INIT;
384 # define gl_lock_init(NAME) \
385 if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
386 # define gl_lock_lock(NAME) \
387 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
388 # define gl_lock_unlock(NAME) \
389 if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
390 # define gl_lock_destroy(NAME) \
393 /* ------------------------- gl_rwlock_t datatype ------------------------- */
395 typedef pth_rwlock_t gl_rwlock_t;
396 # define gl_rwlock_define(STORAGECLASS, NAME) \
397 STORAGECLASS pth_rwlock_t NAME;
398 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
399 STORAGECLASS pth_rwlock_t NAME = PTH_RWLOCK_INIT;
400 # define gl_rwlock_init(NAME) \
401 if (pth_in_use() && !pth_rwlock_init (&NAME)) abort ()
402 # define gl_rwlock_rdlock(NAME) \
403 if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) abort ()
404 # define gl_rwlock_wrlock(NAME) \
405 if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) abort ()
406 # define gl_rwlock_unlock(NAME) \
407 if (pth_in_use() && !pth_rwlock_release (&NAME)) abort ()
408 # define gl_rwlock_destroy(NAME) \
411 /* --------------------- gl_recursive_lock_t datatype --------------------- */
413 /* In Pth, mutexes are recursive by default. */
414 typedef pth_mutex_t gl_recursive_lock_t;
415 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
416 STORAGECLASS pth_mutex_t NAME;
417 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
418 STORAGECLASS pth_mutex_t NAME = PTH_MUTEX_INIT;
419 # define gl_recursive_lock_init(NAME) \
420 if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
421 # define gl_recursive_lock_lock(NAME) \
422 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
423 # define gl_recursive_lock_unlock(NAME) \
424 if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
425 # define gl_recursive_lock_destroy(NAME) \
428 /* -------------------------- gl_once_t datatype -------------------------- */
430 typedef pth_once_t gl_once_t;
431 # define gl_once_define(STORAGECLASS, NAME) \
432 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
433 # define gl_once(NAME, INITFUNCTION) \
438 void (*gl_once_temp) (void) = INITFUNCTION; \
439 if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
444 if (glthread_once_singlethreaded (&NAME)) \
449 extern void glthread_once_call (void *arg);
450 extern int glthread_once_singlethreaded (pth_once_t *once_control);
454 /* ========================================================================= */
456 #if USE_SOLARIS_THREADS
458 /* Use the old Solaris threads library. */
464 # if USE_SOLARIS_THREADS_WEAK
466 /* Use weak references to the old Solaris threads library. */
468 # pragma weak mutex_init
469 # pragma weak mutex_lock
470 # pragma weak mutex_unlock
471 # pragma weak mutex_destroy
472 # pragma weak rwlock_init
473 # pragma weak rw_rdlock
474 # pragma weak rw_wrlock
475 # pragma weak rw_unlock
476 # pragma weak rwlock_destroy
477 # pragma weak thr_self
479 # pragma weak thr_suspend
480 # define thread_in_use() (thr_suspend != NULL)
484 # define thread_in_use() 1
488 /* -------------------------- gl_lock_t datatype -------------------------- */
490 typedef mutex_t gl_lock_t;
491 # define gl_lock_define(STORAGECLASS, NAME) \
492 STORAGECLASS mutex_t NAME;
493 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
494 STORAGECLASS mutex_t NAME = DEFAULTMUTEX;
495 # define gl_lock_init(NAME) \
496 if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
497 # define gl_lock_lock(NAME) \
498 if (thread_in_use () && mutex_lock (&NAME) != 0) abort ()
499 # define gl_lock_unlock(NAME) \
500 if (thread_in_use () && mutex_unlock (&NAME) != 0) abort ()
501 # define gl_lock_destroy(NAME) \
502 if (thread_in_use () && mutex_destroy (&NAME) != 0) abort ()
504 /* ------------------------- gl_rwlock_t datatype ------------------------- */
506 typedef rwlock_t gl_rwlock_t;
507 # define gl_rwlock_define(STORAGECLASS, NAME) \
508 STORAGECLASS rwlock_t NAME;
509 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
510 STORAGECLASS rwlock_t NAME = DEFAULTRWLOCK;
511 # define gl_rwlock_init(NAME) \
512 if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
513 # define gl_rwlock_rdlock(NAME) \
514 if (thread_in_use () && rw_rdlock (&NAME) != 0) abort ()
515 # define gl_rwlock_wrlock(NAME) \
516 if (thread_in_use () && rw_wrlock (&NAME) != 0) abort ()
517 # define gl_rwlock_unlock(NAME) \
518 if (thread_in_use () && rw_unlock (&NAME) != 0) abort ()
519 # define gl_rwlock_destroy(NAME) \
520 if (thread_in_use () && rwlock_destroy (&NAME) != 0) abort ()
522 /* --------------------- gl_recursive_lock_t datatype --------------------- */
524 /* Old Solaris threads did not have recursive locks.
525 We have to implement them ourselves. */
534 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
535 STORAGECLASS gl_recursive_lock_t NAME;
536 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
537 STORAGECLASS gl_recursive_lock_t NAME = { DEFAULTMUTEX, (thread_t) 0, 0 };
538 # define gl_recursive_lock_init(NAME) \
539 if (thread_in_use ()) glthread_recursive_lock_init (&NAME)
540 # define gl_recursive_lock_lock(NAME) \
541 if (thread_in_use ()) glthread_recursive_lock_lock (&NAME)
542 # define gl_recursive_lock_unlock(NAME) \
543 if (thread_in_use ()) glthread_recursive_lock_unlock (&NAME)
544 # define gl_recursive_lock_destroy(NAME) \
545 if (thread_in_use ()) glthread_recursive_lock_destroy (&NAME)
546 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
547 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
548 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
549 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
551 /* -------------------------- gl_once_t datatype -------------------------- */
559 # define gl_once_define(STORAGECLASS, NAME) \
560 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
561 # define gl_once(NAME, INITFUNCTION) \
564 if (thread_in_use ()) \
566 glthread_once (&NAME, INITFUNCTION); \
570 if (glthread_once_singlethreaded (&NAME)) \
575 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
576 extern int glthread_once_singlethreaded (gl_once_t *once_control);
580 /* ========================================================================= */
582 #if USE_WIN32_THREADS
584 # include <windows.h>
586 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
587 Semaphore types, because
588 - we need only to synchronize inside a single process (address space),
589 not inter-process locking,
590 - we don't need to support trylock operations. (TryEnterCriticalSection
591 does not work on Windows 95/98/ME. Packages that need trylock usually
592 define their own mutex type.) */
594 /* There is no way to statically initialize a CRITICAL_SECTION. It needs
595 to be done lazily, once only. For this we need spinlocks. */
597 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
599 /* -------------------------- gl_lock_t datatype -------------------------- */
603 gl_spinlock_t guard; /* protects the initialization */
604 CRITICAL_SECTION lock;
607 # define gl_lock_define(STORAGECLASS, NAME) \
608 STORAGECLASS gl_lock_t NAME;
609 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
610 STORAGECLASS gl_lock_t NAME = { { 0, -1 } };
611 # define gl_lock_init(NAME) \
612 glthread_lock_init (&NAME)
613 # define gl_lock_lock(NAME) \
614 glthread_lock_lock (&NAME)
615 # define gl_lock_unlock(NAME) \
616 glthread_lock_unlock (&NAME)
617 # define gl_lock_destroy(NAME) \
618 glthread_lock_destroy (&NAME)
619 extern void glthread_lock_init (gl_lock_t *lock);
620 extern void glthread_lock_lock (gl_lock_t *lock);
621 extern void glthread_lock_unlock (gl_lock_t *lock);
622 extern void glthread_lock_destroy (gl_lock_t *lock);
624 /* ------------------------- gl_rwlock_t datatype ------------------------- */
626 /* It is impossible to implement read-write locks using plain locks, without
627 introducing an extra thread dedicated to managing read-write locks.
628 Therefore here we need to use the low-level Event type. */
632 HANDLE *array; /* array of waiting threads, each represented by an event */
633 unsigned int count; /* number of waiting threads */
634 unsigned int alloc; /* length of allocated array */
635 unsigned int offset; /* index of first waiting thread in array */
640 gl_spinlock_t guard; /* protects the initialization */
641 CRITICAL_SECTION lock; /* protects the remaining fields */
642 gl_waitqueue_t waiting_readers; /* waiting readers */
643 gl_waitqueue_t waiting_writers; /* waiting writers */
644 int runcount; /* number of readers running, or -1 when a writer runs */
647 # define gl_rwlock_define(STORAGECLASS, NAME) \
648 STORAGECLASS gl_rwlock_t NAME;
649 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
650 STORAGECLASS gl_rwlock_t NAME = { { 0, -1 } };
651 # define gl_rwlock_init(NAME) \
652 glthread_rwlock_init (&NAME)
653 # define gl_rwlock_rdlock(NAME) \
654 glthread_rwlock_rdlock (&NAME)
655 # define gl_rwlock_wrlock(NAME) \
656 glthread_rwlock_wrlock (&NAME)
657 # define gl_rwlock_unlock(NAME) \
658 glthread_rwlock_unlock (&NAME)
659 # define gl_rwlock_destroy(NAME) \
660 glthread_rwlock_destroy (&NAME)
661 extern void glthread_rwlock_init (gl_rwlock_t *lock);
662 extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
663 extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
664 extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
665 extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
667 /* --------------------- gl_recursive_lock_t datatype --------------------- */
669 /* The Win32 documentation says that CRITICAL_SECTION already implements a
670 recursive lock. But we need not rely on it: It's easy to implement a
671 recursive lock without this assumption. */
675 gl_spinlock_t guard; /* protects the initialization */
678 CRITICAL_SECTION lock;
681 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
682 STORAGECLASS gl_recursive_lock_t NAME;
683 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
684 STORAGECLASS gl_recursive_lock_t NAME = { { 0, -1 }, 0, 0 };
685 # define gl_recursive_lock_init(NAME) \
686 glthread_recursive_lock_init (&NAME)
687 # define gl_recursive_lock_lock(NAME) \
688 glthread_recursive_lock_lock (&NAME)
689 # define gl_recursive_lock_unlock(NAME) \
690 glthread_recursive_lock_unlock (&NAME)
691 # define gl_recursive_lock_destroy(NAME) \
692 glthread_recursive_lock_destroy (&NAME)
693 extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
694 extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
695 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
696 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
698 /* -------------------------- gl_once_t datatype -------------------------- */
703 volatile long started;
704 CRITICAL_SECTION lock;
707 # define gl_once_define(STORAGECLASS, NAME) \
708 STORAGECLASS gl_once_t NAME = { -1, -1 };
709 # define gl_once(NAME, INITFUNCTION) \
710 glthread_once (&NAME, INITFUNCTION)
711 extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
715 /* ========================================================================= */
717 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
719 /* Provide dummy implementation if threads are not supported. */
721 /* -------------------------- gl_lock_t datatype -------------------------- */
723 typedef int gl_lock_t;
724 # define gl_lock_define(STORAGECLASS, NAME)
725 # define gl_lock_define_initialized(STORAGECLASS, NAME)
726 # define gl_lock_init(NAME)
727 # define gl_lock_lock(NAME)
728 # define gl_lock_unlock(NAME)
730 /* ------------------------- gl_rwlock_t datatype ------------------------- */
732 typedef int gl_rwlock_t;
733 # define gl_rwlock_define(STORAGECLASS, NAME)
734 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
735 # define gl_rwlock_init(NAME)
736 # define gl_rwlock_rdlock(NAME)
737 # define gl_rwlock_wrlock(NAME)
738 # define gl_rwlock_unlock(NAME)
740 /* --------------------- gl_recursive_lock_t datatype --------------------- */
742 typedef int gl_recursive_lock_t;
743 # define gl_recursive_lock_define(STORAGECLASS, NAME)
744 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
745 # define gl_recursive_lock_init(NAME)
746 # define gl_recursive_lock_lock(NAME)
747 # define gl_recursive_lock_unlock(NAME)
749 /* -------------------------- gl_once_t datatype -------------------------- */
751 typedef int gl_once_t;
752 # define gl_once_define(STORAGECLASS, NAME) \
753 STORAGECLASS gl_once_t NAME = 0;
754 # define gl_once(NAME, INITFUNCTION) \