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);
65 /* ========================================================================= */
69 /* Use the POSIX threads library. */
74 # if PTHREAD_IN_USE_DETECTION_HARD
76 /* The pthread_in_use() detection needs to be done at runtime. */
77 # define pthread_in_use() \
79 extern int glthread_in_use (void);
83 # if USE_POSIX_THREADS_WEAK
85 /* Use weak references to the POSIX threads library. */
87 /* Weak references avoid dragging in external libraries if the other parts
88 of the program don't use them. Here we use them, because we don't want
89 every program that uses libintl to depend on libpthread. This assumes
90 that libpthread would not be loaded after libintl; i.e. if libintl is
91 loaded first, by an executable that does not depend on libpthread, and
92 then a module is dynamically loaded that depends on libpthread, libintl
93 will not be multithread-safe. */
95 /* The way to test at runtime whether libpthread is present is to test
96 whether a function pointer's value, such as &pthread_mutex_init, is
97 non-NULL. However, some versions of GCC have a bug through which, in
98 PIC mode, &foo != NULL always evaluates to true if there is a direct
99 call to foo(...) in the same function. To avoid this, we test the
100 address of a function in libpthread that we don't use. */
102 # pragma weak pthread_mutex_init
103 # pragma weak pthread_mutex_lock
104 # pragma weak pthread_mutex_unlock
105 # pragma weak pthread_mutex_destroy
106 # pragma weak pthread_rwlock_init
107 # pragma weak pthread_rwlock_rdlock
108 # pragma weak pthread_rwlock_wrlock
109 # pragma weak pthread_rwlock_unlock
110 # pragma weak pthread_rwlock_destroy
111 # pragma weak pthread_once
112 # pragma weak pthread_cond_init
113 # pragma weak pthread_cond_wait
114 # pragma weak pthread_cond_signal
115 # pragma weak pthread_cond_broadcast
116 # pragma weak pthread_cond_destroy
117 # pragma weak pthread_mutexattr_init
118 # pragma weak pthread_mutexattr_settype
119 # pragma weak pthread_mutexattr_destroy
120 # ifndef pthread_self
121 # pragma weak pthread_self
124 # if !PTHREAD_IN_USE_DETECTION_HARD
125 # pragma weak pthread_cancel
126 # define pthread_in_use() (pthread_cancel != NULL)
131 # if !PTHREAD_IN_USE_DETECTION_HARD
132 # define pthread_in_use() 1
137 /* -------------------------- gl_lock_t datatype -------------------------- */
139 typedef pthread_mutex_t gl_lock_t
;
140 # define gl_lock_define(STORAGECLASS, NAME) \
141 STORAGECLASS pthread_mutex_t NAME;
142 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
143 STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
144 # define gl_lock_initializer \
145 PTHREAD_MUTEX_INITIALIZER
146 # define gl_lock_init(NAME) \
147 if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
148 # define gl_lock_lock(NAME) \
149 if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
150 # define gl_lock_unlock(NAME) \
151 if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
152 # define gl_lock_destroy(NAME) \
153 if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
155 /* ------------------------- gl_rwlock_t datatype ------------------------- */
157 # if HAVE_PTHREAD_RWLOCK
159 # ifdef PTHREAD_RWLOCK_INITIALIZER
161 typedef pthread_rwlock_t gl_rwlock_t
;
162 # define gl_rwlock_define(STORAGECLASS, NAME) \
163 STORAGECLASS pthread_rwlock_t NAME;
164 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
165 STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
166 # define gl_rwlock_initializer \
167 PTHREAD_RWLOCK_INITIALIZER
168 # define gl_rwlock_init(NAME) \
169 if (pthread_in_use () && pthread_rwlock_init (&NAME, NULL) != 0) abort ()
170 # define gl_rwlock_rdlock(NAME) \
171 if (pthread_in_use () && pthread_rwlock_rdlock (&NAME) != 0) abort ()
172 # define gl_rwlock_wrlock(NAME) \
173 if (pthread_in_use () && pthread_rwlock_wrlock (&NAME) != 0) abort ()
174 # define gl_rwlock_unlock(NAME) \
175 if (pthread_in_use () && pthread_rwlock_unlock (&NAME) != 0) abort ()
176 # define gl_rwlock_destroy(NAME) \
177 if (pthread_in_use () && pthread_rwlock_destroy (&NAME) != 0) abort ()
184 pthread_mutex_t guard
; /* protects the initialization */
185 pthread_rwlock_t rwlock
; /* read-write lock */
188 # define gl_rwlock_define(STORAGECLASS, NAME) \
189 STORAGECLASS gl_rwlock_t NAME;
190 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
191 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
192 # define gl_rwlock_initializer \
193 { 0, PTHREAD_MUTEX_INITIALIZER }
194 # define gl_rwlock_init(NAME) \
195 if (pthread_in_use ()) glthread_rwlock_init (&NAME)
196 # define gl_rwlock_rdlock(NAME) \
197 if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
198 # define gl_rwlock_wrlock(NAME) \
199 if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
200 # define gl_rwlock_unlock(NAME) \
201 if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
202 # define gl_rwlock_destroy(NAME) \
203 if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
204 extern void glthread_rwlock_init (gl_rwlock_t
*lock
);
205 extern void glthread_rwlock_rdlock (gl_rwlock_t
*lock
);
206 extern void glthread_rwlock_wrlock (gl_rwlock_t
*lock
);
207 extern void glthread_rwlock_unlock (gl_rwlock_t
*lock
);
208 extern void glthread_rwlock_destroy (gl_rwlock_t
*lock
);
216 pthread_mutex_t lock
; /* protects the remaining fields */
217 pthread_cond_t waiting_readers
; /* waiting readers */
218 pthread_cond_t waiting_writers
; /* waiting writers */
219 unsigned int waiting_writers_count
; /* number of waiting writers */
220 int runcount
; /* number of readers running, or -1 when a writer runs */
223 # define gl_rwlock_define(STORAGECLASS, NAME) \
224 STORAGECLASS gl_rwlock_t NAME;
225 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
226 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
227 # define gl_rwlock_initializer \
228 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
229 # define gl_rwlock_init(NAME) \
230 if (pthread_in_use ()) glthread_rwlock_init (&NAME)
231 # define gl_rwlock_rdlock(NAME) \
232 if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
233 # define gl_rwlock_wrlock(NAME) \
234 if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
235 # define gl_rwlock_unlock(NAME) \
236 if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
237 # define gl_rwlock_destroy(NAME) \
238 if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
239 extern void glthread_rwlock_init (gl_rwlock_t
*lock
);
240 extern void glthread_rwlock_rdlock (gl_rwlock_t
*lock
);
241 extern void glthread_rwlock_wrlock (gl_rwlock_t
*lock
);
242 extern void glthread_rwlock_unlock (gl_rwlock_t
*lock
);
243 extern void glthread_rwlock_destroy (gl_rwlock_t
*lock
);
247 /* --------------------- gl_recursive_lock_t datatype --------------------- */
249 # if HAVE_PTHREAD_MUTEX_RECURSIVE
251 # if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
253 typedef pthread_mutex_t gl_recursive_lock_t
;
254 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
255 STORAGECLASS pthread_mutex_t NAME;
256 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
257 STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
258 # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
259 # define gl_recursive_lock_initializer \
260 PTHREAD_RECURSIVE_MUTEX_INITIALIZER
262 # define gl_recursive_lock_initializer \
263 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
265 # define gl_recursive_lock_init(NAME) \
266 if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
267 # define gl_recursive_lock_lock(NAME) \
268 if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
269 # define gl_recursive_lock_unlock(NAME) \
270 if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
271 # define gl_recursive_lock_destroy(NAME) \
272 if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
278 pthread_mutex_t recmutex
; /* recursive mutex */
279 pthread_mutex_t guard
; /* protects the initialization */
283 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
284 STORAGECLASS gl_recursive_lock_t NAME;
285 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
286 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
287 # define gl_recursive_lock_initializer \
288 { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
289 # define gl_recursive_lock_init(NAME) \
290 if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
291 # define gl_recursive_lock_lock(NAME) \
292 if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
293 # define gl_recursive_lock_unlock(NAME) \
294 if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
295 # define gl_recursive_lock_destroy(NAME) \
296 if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
297 extern void glthread_recursive_lock_init (gl_recursive_lock_t
*lock
);
298 extern void glthread_recursive_lock_lock (gl_recursive_lock_t
*lock
);
299 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t
*lock
);
300 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t
*lock
);
306 /* Old versions of POSIX threads on Solaris did not have recursive locks.
307 We have to implement them ourselves. */
311 pthread_mutex_t mutex
;
316 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
317 STORAGECLASS gl_recursive_lock_t NAME;
318 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
319 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
320 # define gl_recursive_lock_initializer \
321 { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
322 # define gl_recursive_lock_init(NAME) \
323 if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
324 # define gl_recursive_lock_lock(NAME) \
325 if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
326 # define gl_recursive_lock_unlock(NAME) \
327 if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
328 # define gl_recursive_lock_destroy(NAME) \
329 if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
330 extern void glthread_recursive_lock_init (gl_recursive_lock_t
*lock
);
331 extern void glthread_recursive_lock_lock (gl_recursive_lock_t
*lock
);
332 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t
*lock
);
333 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t
*lock
);
337 /* -------------------------- gl_once_t datatype -------------------------- */
339 typedef pthread_once_t gl_once_t
;
340 # define gl_once_define(STORAGECLASS, NAME) \
341 STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
342 # define gl_once(NAME, INITFUNCTION) \
345 if (pthread_in_use ()) \
347 if (pthread_once (&NAME, INITFUNCTION) != 0) \
352 if (glthread_once_singlethreaded (&NAME)) \
357 extern int glthread_once_singlethreaded (pthread_once_t
*once_control
);
361 /* ========================================================================= */
365 /* Use the GNU Pth threads library. */
370 # if USE_PTH_THREADS_WEAK
372 /* Use weak references to the GNU Pth threads library. */
374 # pragma weak pth_mutex_init
375 # pragma weak pth_mutex_acquire
376 # pragma weak pth_mutex_release
377 # pragma weak pth_rwlock_init
378 # pragma weak pth_rwlock_acquire
379 # pragma weak pth_rwlock_release
380 # pragma weak pth_once
382 # pragma weak pth_cancel
383 # define pth_in_use() (pth_cancel != NULL)
387 # define pth_in_use() 1
391 /* -------------------------- gl_lock_t datatype -------------------------- */
393 typedef pth_mutex_t gl_lock_t
;
394 # define gl_lock_define(STORAGECLASS, NAME) \
395 STORAGECLASS pth_mutex_t NAME;
396 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
397 STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
398 # define gl_lock_initializer \
400 # define gl_lock_init(NAME) \
401 if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
402 # define gl_lock_lock(NAME) \
403 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
404 # define gl_lock_unlock(NAME) \
405 if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
406 # define gl_lock_destroy(NAME) \
409 /* ------------------------- gl_rwlock_t datatype ------------------------- */
411 typedef pth_rwlock_t gl_rwlock_t
;
412 # define gl_rwlock_define(STORAGECLASS, NAME) \
413 STORAGECLASS pth_rwlock_t NAME;
414 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
415 STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
416 # define gl_rwlock_initializer \
418 # define gl_rwlock_init(NAME) \
419 if (pth_in_use() && !pth_rwlock_init (&NAME)) abort ()
420 # define gl_rwlock_rdlock(NAME) \
421 if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) abort ()
422 # define gl_rwlock_wrlock(NAME) \
423 if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) abort ()
424 # define gl_rwlock_unlock(NAME) \
425 if (pth_in_use() && !pth_rwlock_release (&NAME)) abort ()
426 # define gl_rwlock_destroy(NAME) \
429 /* --------------------- gl_recursive_lock_t datatype --------------------- */
431 /* In Pth, mutexes are recursive by default. */
432 typedef pth_mutex_t gl_recursive_lock_t
;
433 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
434 STORAGECLASS pth_mutex_t NAME;
435 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
436 STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
437 # define gl_recursive_lock_initializer \
439 # define gl_recursive_lock_init(NAME) \
440 if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
441 # define gl_recursive_lock_lock(NAME) \
442 if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
443 # define gl_recursive_lock_unlock(NAME) \
444 if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
445 # define gl_recursive_lock_destroy(NAME) \
448 /* -------------------------- gl_once_t datatype -------------------------- */
450 typedef pth_once_t gl_once_t
;
451 # define gl_once_define(STORAGECLASS, NAME) \
452 STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
453 # define gl_once(NAME, INITFUNCTION) \
458 void (*gl_once_temp) (void) = INITFUNCTION; \
459 if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
464 if (glthread_once_singlethreaded (&NAME)) \
469 extern void glthread_once_call (void *arg
);
470 extern int glthread_once_singlethreaded (pth_once_t
*once_control
);
474 /* ========================================================================= */
476 #if USE_SOLARIS_THREADS
478 /* Use the old Solaris threads library. */
484 # if USE_SOLARIS_THREADS_WEAK
486 /* Use weak references to the old Solaris threads library. */
488 # pragma weak mutex_init
489 # pragma weak mutex_lock
490 # pragma weak mutex_unlock
491 # pragma weak mutex_destroy
492 # pragma weak rwlock_init
493 # pragma weak rw_rdlock
494 # pragma weak rw_wrlock
495 # pragma weak rw_unlock
496 # pragma weak rwlock_destroy
497 # pragma weak thr_self
499 # pragma weak thr_suspend
500 # define thread_in_use() (thr_suspend != NULL)
504 # define thread_in_use() 1
508 /* -------------------------- gl_lock_t datatype -------------------------- */
510 typedef mutex_t gl_lock_t
;
511 # define gl_lock_define(STORAGECLASS, NAME) \
512 STORAGECLASS mutex_t NAME;
513 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
514 STORAGECLASS mutex_t NAME = gl_lock_initializer;
515 # define gl_lock_initializer \
517 # define gl_lock_init(NAME) \
518 if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
519 # define gl_lock_lock(NAME) \
520 if (thread_in_use () && mutex_lock (&NAME) != 0) abort ()
521 # define gl_lock_unlock(NAME) \
522 if (thread_in_use () && mutex_unlock (&NAME) != 0) abort ()
523 # define gl_lock_destroy(NAME) \
524 if (thread_in_use () && mutex_destroy (&NAME) != 0) abort ()
526 /* ------------------------- gl_rwlock_t datatype ------------------------- */
528 typedef rwlock_t gl_rwlock_t
;
529 # define gl_rwlock_define(STORAGECLASS, NAME) \
530 STORAGECLASS rwlock_t NAME;
531 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
532 STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
533 # define gl_rwlock_initializer \
535 # define gl_rwlock_init(NAME) \
536 if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
537 # define gl_rwlock_rdlock(NAME) \
538 if (thread_in_use () && rw_rdlock (&NAME) != 0) abort ()
539 # define gl_rwlock_wrlock(NAME) \
540 if (thread_in_use () && rw_wrlock (&NAME) != 0) abort ()
541 # define gl_rwlock_unlock(NAME) \
542 if (thread_in_use () && rw_unlock (&NAME) != 0) abort ()
543 # define gl_rwlock_destroy(NAME) \
544 if (thread_in_use () && rwlock_destroy (&NAME) != 0) abort ()
546 /* --------------------- gl_recursive_lock_t datatype --------------------- */
548 /* Old Solaris threads did not have recursive locks.
549 We have to implement them ourselves. */
558 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
559 STORAGECLASS gl_recursive_lock_t NAME;
560 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
561 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
562 # define gl_recursive_lock_initializer \
563 { DEFAULTMUTEX, (thread_t) 0, 0 }
564 # define gl_recursive_lock_init(NAME) \
565 if (thread_in_use ()) glthread_recursive_lock_init (&NAME)
566 # define gl_recursive_lock_lock(NAME) \
567 if (thread_in_use ()) glthread_recursive_lock_lock (&NAME)
568 # define gl_recursive_lock_unlock(NAME) \
569 if (thread_in_use ()) glthread_recursive_lock_unlock (&NAME)
570 # define gl_recursive_lock_destroy(NAME) \
571 if (thread_in_use ()) glthread_recursive_lock_destroy (&NAME)
572 extern void glthread_recursive_lock_init (gl_recursive_lock_t
*lock
);
573 extern void glthread_recursive_lock_lock (gl_recursive_lock_t
*lock
);
574 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t
*lock
);
575 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t
*lock
);
577 /* -------------------------- gl_once_t datatype -------------------------- */
585 # define gl_once_define(STORAGECLASS, NAME) \
586 STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
587 # define gl_once(NAME, INITFUNCTION) \
590 if (thread_in_use ()) \
592 glthread_once (&NAME, INITFUNCTION); \
596 if (glthread_once_singlethreaded (&NAME)) \
601 extern void glthread_once (gl_once_t
*once_control
, void (*initfunction
) (void));
602 extern int glthread_once_singlethreaded (gl_once_t
*once_control
);
606 /* ========================================================================= */
608 #if USE_WIN32_THREADS
610 # include <windows.h>
612 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
613 Semaphore types, because
614 - we need only to synchronize inside a single process (address space),
615 not inter-process locking,
616 - we don't need to support trylock operations. (TryEnterCriticalSection
617 does not work on Windows 95/98/ME. Packages that need trylock usually
618 define their own mutex type.) */
620 /* There is no way to statically initialize a CRITICAL_SECTION. It needs
621 to be done lazily, once only. For this we need spinlocks. */
623 typedef struct { volatile int done
; volatile long started
; } gl_spinlock_t
;
625 /* -------------------------- gl_lock_t datatype -------------------------- */
629 gl_spinlock_t guard
; /* protects the initialization */
630 CRITICAL_SECTION lock
;
633 # define gl_lock_define(STORAGECLASS, NAME) \
634 STORAGECLASS gl_lock_t NAME;
635 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
636 STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
637 # define gl_lock_initializer \
639 # define gl_lock_init(NAME) \
640 glthread_lock_init (&NAME)
641 # define gl_lock_lock(NAME) \
642 glthread_lock_lock (&NAME)
643 # define gl_lock_unlock(NAME) \
644 glthread_lock_unlock (&NAME)
645 # define gl_lock_destroy(NAME) \
646 glthread_lock_destroy (&NAME)
647 extern void glthread_lock_init (gl_lock_t
*lock
);
648 extern void glthread_lock_lock (gl_lock_t
*lock
);
649 extern void glthread_lock_unlock (gl_lock_t
*lock
);
650 extern void glthread_lock_destroy (gl_lock_t
*lock
);
652 /* ------------------------- gl_rwlock_t datatype ------------------------- */
654 /* It is impossible to implement read-write locks using plain locks, without
655 introducing an extra thread dedicated to managing read-write locks.
656 Therefore here we need to use the low-level Event type. */
660 HANDLE
*array
; /* array of waiting threads, each represented by an event */
661 unsigned int count
; /* number of waiting threads */
662 unsigned int alloc
; /* length of allocated array */
663 unsigned int offset
; /* index of first waiting thread in array */
668 gl_spinlock_t guard
; /* protects the initialization */
669 CRITICAL_SECTION lock
; /* protects the remaining fields */
670 gl_waitqueue_t waiting_readers
; /* waiting readers */
671 gl_waitqueue_t waiting_writers
; /* waiting writers */
672 int runcount
; /* number of readers running, or -1 when a writer runs */
675 # define gl_rwlock_define(STORAGECLASS, NAME) \
676 STORAGECLASS gl_rwlock_t NAME;
677 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
678 STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
679 # define gl_rwlock_initializer \
681 # define gl_rwlock_init(NAME) \
682 glthread_rwlock_init (&NAME)
683 # define gl_rwlock_rdlock(NAME) \
684 glthread_rwlock_rdlock (&NAME)
685 # define gl_rwlock_wrlock(NAME) \
686 glthread_rwlock_wrlock (&NAME)
687 # define gl_rwlock_unlock(NAME) \
688 glthread_rwlock_unlock (&NAME)
689 # define gl_rwlock_destroy(NAME) \
690 glthread_rwlock_destroy (&NAME)
691 extern void glthread_rwlock_init (gl_rwlock_t
*lock
);
692 extern void glthread_rwlock_rdlock (gl_rwlock_t
*lock
);
693 extern void glthread_rwlock_wrlock (gl_rwlock_t
*lock
);
694 extern void glthread_rwlock_unlock (gl_rwlock_t
*lock
);
695 extern void glthread_rwlock_destroy (gl_rwlock_t
*lock
);
697 /* --------------------- gl_recursive_lock_t datatype --------------------- */
699 /* The Win32 documentation says that CRITICAL_SECTION already implements a
700 recursive lock. But we need not rely on it: It's easy to implement a
701 recursive lock without this assumption. */
705 gl_spinlock_t guard
; /* protects the initialization */
708 CRITICAL_SECTION lock
;
711 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
712 STORAGECLASS gl_recursive_lock_t NAME;
713 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
714 STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
715 # define gl_recursive_lock_initializer \
717 # define gl_recursive_lock_init(NAME) \
718 glthread_recursive_lock_init (&NAME)
719 # define gl_recursive_lock_lock(NAME) \
720 glthread_recursive_lock_lock (&NAME)
721 # define gl_recursive_lock_unlock(NAME) \
722 glthread_recursive_lock_unlock (&NAME)
723 # define gl_recursive_lock_destroy(NAME) \
724 glthread_recursive_lock_destroy (&NAME)
725 extern void glthread_recursive_lock_init (gl_recursive_lock_t
*lock
);
726 extern void glthread_recursive_lock_lock (gl_recursive_lock_t
*lock
);
727 extern void glthread_recursive_lock_unlock (gl_recursive_lock_t
*lock
);
728 extern void glthread_recursive_lock_destroy (gl_recursive_lock_t
*lock
);
730 /* -------------------------- gl_once_t datatype -------------------------- */
735 volatile long started
;
736 CRITICAL_SECTION lock
;
739 # define gl_once_define(STORAGECLASS, NAME) \
740 STORAGECLASS gl_once_t NAME = { -1, -1 };
741 # define gl_once(NAME, INITFUNCTION) \
742 glthread_once (&NAME, INITFUNCTION)
743 extern void glthread_once (gl_once_t
*once_control
, void (*initfunction
) (void));
747 /* ========================================================================= */
749 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
751 /* Provide dummy implementation if threads are not supported. */
753 /* -------------------------- gl_lock_t datatype -------------------------- */
755 typedef int gl_lock_t
;
756 # define gl_lock_define(STORAGECLASS, NAME)
757 # define gl_lock_define_initialized(STORAGECLASS, NAME)
758 # define gl_lock_init(NAME)
759 # define gl_lock_lock(NAME)
760 # define gl_lock_unlock(NAME)
762 /* ------------------------- gl_rwlock_t datatype ------------------------- */
764 typedef int gl_rwlock_t
;
765 # define gl_rwlock_define(STORAGECLASS, NAME)
766 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
767 # define gl_rwlock_init(NAME)
768 # define gl_rwlock_rdlock(NAME)
769 # define gl_rwlock_wrlock(NAME)
770 # define gl_rwlock_unlock(NAME)
772 /* --------------------- gl_recursive_lock_t datatype --------------------- */
774 typedef int gl_recursive_lock_t
;
775 # define gl_recursive_lock_define(STORAGECLASS, NAME)
776 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
777 # define gl_recursive_lock_init(NAME)
778 # define gl_recursive_lock_lock(NAME)
779 # define gl_recursive_lock_unlock(NAME)
781 /* -------------------------- gl_once_t datatype -------------------------- */
783 typedef int gl_once_t
;
784 # define gl_once_define(STORAGECLASS, NAME) \
785 STORAGECLASS gl_once_t NAME = 0;
786 # define gl_once(NAME, INITFUNCTION) \
799 /* ========================================================================= */