1
/* Locking in multithreaded situations.
2
Copyright (C) 2005-2006 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. */
78
# if PTHREAD_IN_USE_DETECTION_HARD
80
/* The pthread_in_use() detection needs to be done at runtime. */
81
# define pthread_in_use() \
83
extern int glthread_in_use (void);
87
# if USE_POSIX_THREADS_WEAK
89
/* Use weak references to the POSIX threads library. */
91
/* Weak references avoid dragging in external libraries if the other parts
92
of the program don't use them. Here we use them, because we don't want
93
every program that uses libintl to depend on libpthread. This assumes
94
that libpthread would not be loaded after libintl; i.e. if libintl is
95
loaded first, by an executable that does not depend on libpthread, and
96
then a module is dynamically loaded that depends on libpthread, libintl
97
will not be multithread-safe. */
99
/* The way to test at runtime whether libpthread is present is to test
100
whether a function pointer's value, such as &pthread_mutex_init, is
101
non-NULL. However, some versions of GCC have a bug through which, in
102
PIC mode, &foo != NULL always evaluates to true if there is a direct
103
call to foo(...) in the same function. To avoid this, we test the
104
address of a function in libpthread that we don't use. */
106
# pragma weak pthread_mutex_init
107
# pragma weak pthread_mutex_lock
108
# pragma weak pthread_mutex_unlock
109
# pragma weak pthread_mutex_destroy
110
# pragma weak pthread_rwlock_init
111
# pragma weak pthread_rwlock_rdlock
112
# pragma weak pthread_rwlock_wrlock
113
# pragma weak pthread_rwlock_unlock
114
# pragma weak pthread_rwlock_destroy
115
# pragma weak pthread_once
116
# pragma weak pthread_cond_init
117
# pragma weak pthread_cond_wait
118
# pragma weak pthread_cond_signal
119
# pragma weak pthread_cond_broadcast
120
# pragma weak pthread_cond_destroy
121
# pragma weak pthread_mutexattr_init
122
# pragma weak pthread_mutexattr_settype
123
# pragma weak pthread_mutexattr_destroy
124
# ifndef pthread_self
125
# pragma weak pthread_self
128
# if !PTHREAD_IN_USE_DETECTION_HARD
129
# pragma weak pthread_cancel
130
# define pthread_in_use() (pthread_cancel != NULL)
135
# if !PTHREAD_IN_USE_DETECTION_HARD
136
# define pthread_in_use() 1
141
/* -------------------------- gl_lock_t datatype -------------------------- */
143
typedef pthread_mutex_t gl_lock_t;
144
# define gl_lock_define(STORAGECLASS, NAME) \
145
STORAGECLASS pthread_mutex_t NAME;
146
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
147
STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
148
# define gl_lock_initializer \
149
PTHREAD_MUTEX_INITIALIZER
150
# define gl_lock_init(NAME) \
151
if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
152
# define gl_lock_lock(NAME) \
153
if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
154
# define gl_lock_unlock(NAME) \
155
if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
156
# define gl_lock_destroy(NAME) \
157
if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
159
/* ------------------------- gl_rwlock_t datatype ------------------------- */
161
# if HAVE_PTHREAD_RWLOCK
163
# ifdef PTHREAD_RWLOCK_INITIALIZER
165
typedef pthread_rwlock_t gl_rwlock_t;
166
# define gl_rwlock_define(STORAGECLASS, NAME) \
167
STORAGECLASS pthread_rwlock_t NAME;
168
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
169
STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
170
# define gl_rwlock_initializer \
171
PTHREAD_RWLOCK_INITIALIZER
172
# define gl_rwlock_init(NAME) \
173
if (pthread_in_use () && pthread_rwlock_init (&NAME, NULL) != 0) abort ()
174
# define gl_rwlock_rdlock(NAME) \
175
if (pthread_in_use () && pthread_rwlock_rdlock (&NAME) != 0) abort ()
176
# define gl_rwlock_wrlock(NAME) \
177
if (pthread_in_use () && pthread_rwlock_wrlock (&NAME) != 0) abort ()
178
# define gl_rwlock_unlock(NAME) \
179
if (pthread_in_use () && pthread_rwlock_unlock (&NAME) != 0) abort ()
180
# define gl_rwlock_destroy(NAME) \
181
if (pthread_in_use () && pthread_rwlock_destroy (&NAME) != 0) abort ()
188
pthread_mutex_t guard; /* protects the initialization */
189
pthread_rwlock_t rwlock; /* read-write lock */
192
# define gl_rwlock_define(STORAGECLASS, NAME) \
193
STORAGECLASS gl_rwlock_t NAME;
194
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
195
STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
196
# define gl_rwlock_initializer \
197
{ 0, PTHREAD_MUTEX_INITIALIZER }
198
# define gl_rwlock_init(NAME) \
199
if (pthread_in_use ()) glthread_rwlock_init (&NAME)
200
# define gl_rwlock_rdlock(NAME) \
201
if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
202
# define gl_rwlock_wrlock(NAME) \
203
if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
204
# define gl_rwlock_unlock(NAME) \
205
if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
206
# define gl_rwlock_destroy(NAME) \
207
if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
208
extern void glthread_rwlock_init (gl_rwlock_t *lock);
209
extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
210
extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
211
extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
212
extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
220
pthread_mutex_t lock; /* protects the remaining fields */
221
pthread_cond_t waiting_readers; /* waiting readers */
222
pthread_cond_t waiting_writers; /* waiting writers */
223
unsigned int waiting_writers_count; /* number of waiting writers */
224
int runcount; /* number of readers running, or -1 when a writer runs */
227
# define gl_rwlock_define(STORAGECLASS, NAME) \
228
STORAGECLASS gl_rwlock_t NAME;
229
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
230
STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
231
# define gl_rwlock_initializer \
232
{ PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
233
# define gl_rwlock_init(NAME) \
234
if (pthread_in_use ()) glthread_rwlock_init (&NAME)
235
# define gl_rwlock_rdlock(NAME) \
236
if (pthread_in_use ()) glthread_rwlock_rdlock (&NAME)
237
# define gl_rwlock_wrlock(NAME) \
238
if (pthread_in_use ()) glthread_rwlock_wrlock (&NAME)
239
# define gl_rwlock_unlock(NAME) \
240
if (pthread_in_use ()) glthread_rwlock_unlock (&NAME)
241
# define gl_rwlock_destroy(NAME) \
242
if (pthread_in_use ()) glthread_rwlock_destroy (&NAME)
243
extern void glthread_rwlock_init (gl_rwlock_t *lock);
244
extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
245
extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
246
extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
247
extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
251
/* --------------------- gl_recursive_lock_t datatype --------------------- */
253
# if HAVE_PTHREAD_MUTEX_RECURSIVE
255
# if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
257
typedef pthread_mutex_t gl_recursive_lock_t;
258
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
259
STORAGECLASS pthread_mutex_t NAME;
260
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
261
STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
262
# ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
263
# define gl_recursive_lock_initializer \
264
PTHREAD_RECURSIVE_MUTEX_INITIALIZER
266
# define gl_recursive_lock_initializer \
267
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
269
# define gl_recursive_lock_init(NAME) \
270
if (pthread_in_use () && pthread_mutex_init (&NAME, NULL) != 0) abort ()
271
# define gl_recursive_lock_lock(NAME) \
272
if (pthread_in_use () && pthread_mutex_lock (&NAME) != 0) abort ()
273
# define gl_recursive_lock_unlock(NAME) \
274
if (pthread_in_use () && pthread_mutex_unlock (&NAME) != 0) abort ()
275
# define gl_recursive_lock_destroy(NAME) \
276
if (pthread_in_use () && pthread_mutex_destroy (&NAME) != 0) abort ()
282
pthread_mutex_t recmutex; /* recursive mutex */
283
pthread_mutex_t guard; /* protects the initialization */
287
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
288
STORAGECLASS gl_recursive_lock_t NAME;
289
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
290
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
291
# define gl_recursive_lock_initializer \
292
{ PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
293
# define gl_recursive_lock_init(NAME) \
294
if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
295
# define gl_recursive_lock_lock(NAME) \
296
if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
297
# define gl_recursive_lock_unlock(NAME) \
298
if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
299
# define gl_recursive_lock_destroy(NAME) \
300
if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
301
extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
302
extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
303
extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
304
extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
310
/* Old versions of POSIX threads on Solaris did not have recursive locks.
311
We have to implement them ourselves. */
315
pthread_mutex_t mutex;
320
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
321
STORAGECLASS gl_recursive_lock_t NAME;
322
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
323
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
324
# define gl_recursive_lock_initializer \
325
{ PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
326
# define gl_recursive_lock_init(NAME) \
327
if (pthread_in_use ()) glthread_recursive_lock_init (&NAME)
328
# define gl_recursive_lock_lock(NAME) \
329
if (pthread_in_use ()) glthread_recursive_lock_lock (&NAME)
330
# define gl_recursive_lock_unlock(NAME) \
331
if (pthread_in_use ()) glthread_recursive_lock_unlock (&NAME)
332
# define gl_recursive_lock_destroy(NAME) \
333
if (pthread_in_use ()) glthread_recursive_lock_destroy (&NAME)
334
extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
335
extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
336
extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
337
extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
341
/* -------------------------- gl_once_t datatype -------------------------- */
343
typedef pthread_once_t gl_once_t;
344
# define gl_once_define(STORAGECLASS, NAME) \
345
STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
346
# define gl_once(NAME, INITFUNCTION) \
349
if (pthread_in_use ()) \
351
if (pthread_once (&NAME, INITFUNCTION) != 0) \
356
if (glthread_once_singlethreaded (&NAME)) \
361
extern int glthread_once_singlethreaded (pthread_once_t *once_control);
369
/* ========================================================================= */
373
/* Use the GNU Pth threads library. */
382
# if USE_PTH_THREADS_WEAK
384
/* Use weak references to the GNU Pth threads library. */
386
# pragma weak pth_mutex_init
387
# pragma weak pth_mutex_acquire
388
# pragma weak pth_mutex_release
389
# pragma weak pth_rwlock_init
390
# pragma weak pth_rwlock_acquire
391
# pragma weak pth_rwlock_release
392
# pragma weak pth_once
394
# pragma weak pth_cancel
395
# define pth_in_use() (pth_cancel != NULL)
399
# define pth_in_use() 1
403
/* -------------------------- gl_lock_t datatype -------------------------- */
405
typedef pth_mutex_t gl_lock_t;
406
# define gl_lock_define(STORAGECLASS, NAME) \
407
STORAGECLASS pth_mutex_t NAME;
408
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
409
STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
410
# define gl_lock_initializer \
412
# define gl_lock_init(NAME) \
413
if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
414
# define gl_lock_lock(NAME) \
415
if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
416
# define gl_lock_unlock(NAME) \
417
if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
418
# define gl_lock_destroy(NAME) \
421
/* ------------------------- gl_rwlock_t datatype ------------------------- */
423
typedef pth_rwlock_t gl_rwlock_t;
424
# define gl_rwlock_define(STORAGECLASS, NAME) \
425
STORAGECLASS pth_rwlock_t NAME;
426
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
427
STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
428
# define gl_rwlock_initializer \
430
# define gl_rwlock_init(NAME) \
431
if (pth_in_use() && !pth_rwlock_init (&NAME)) abort ()
432
# define gl_rwlock_rdlock(NAME) \
433
if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RD, 0, NULL)) abort ()
434
# define gl_rwlock_wrlock(NAME) \
435
if (pth_in_use() && !pth_rwlock_acquire (&NAME, PTH_RWLOCK_RW, 0, NULL)) abort ()
436
# define gl_rwlock_unlock(NAME) \
437
if (pth_in_use() && !pth_rwlock_release (&NAME)) abort ()
438
# define gl_rwlock_destroy(NAME) \
441
/* --------------------- gl_recursive_lock_t datatype --------------------- */
443
/* In Pth, mutexes are recursive by default. */
444
typedef pth_mutex_t gl_recursive_lock_t;
445
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
446
STORAGECLASS pth_mutex_t NAME;
447
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
448
STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
449
# define gl_recursive_lock_initializer \
451
# define gl_recursive_lock_init(NAME) \
452
if (pth_in_use() && !pth_mutex_init (&NAME)) abort ()
453
# define gl_recursive_lock_lock(NAME) \
454
if (pth_in_use() && !pth_mutex_acquire (&NAME, 0, NULL)) abort ()
455
# define gl_recursive_lock_unlock(NAME) \
456
if (pth_in_use() && !pth_mutex_release (&NAME)) abort ()
457
# define gl_recursive_lock_destroy(NAME) \
460
/* -------------------------- gl_once_t datatype -------------------------- */
462
typedef pth_once_t gl_once_t;
463
# define gl_once_define(STORAGECLASS, NAME) \
464
STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
465
# define gl_once(NAME, INITFUNCTION) \
470
void (*gl_once_temp) (void) = INITFUNCTION; \
471
if (!pth_once (&NAME, glthread_once_call, &gl_once_temp)) \
476
if (glthread_once_singlethreaded (&NAME)) \
481
extern void glthread_once_call (void *arg);
482
extern int glthread_once_singlethreaded (pth_once_t *once_control);
490
/* ========================================================================= */
492
#if USE_SOLARIS_THREADS
494
/* Use the old Solaris threads library. */
504
# if USE_SOLARIS_THREADS_WEAK
506
/* Use weak references to the old Solaris threads library. */
508
# pragma weak mutex_init
509
# pragma weak mutex_lock
510
# pragma weak mutex_unlock
511
# pragma weak mutex_destroy
512
# pragma weak rwlock_init
513
# pragma weak rw_rdlock
514
# pragma weak rw_wrlock
515
# pragma weak rw_unlock
516
# pragma weak rwlock_destroy
517
# pragma weak thr_self
519
# pragma weak thr_suspend
520
# define thread_in_use() (thr_suspend != NULL)
524
# define thread_in_use() 1
528
/* -------------------------- gl_lock_t datatype -------------------------- */
530
typedef mutex_t gl_lock_t;
531
# define gl_lock_define(STORAGECLASS, NAME) \
532
STORAGECLASS mutex_t NAME;
533
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
534
STORAGECLASS mutex_t NAME = gl_lock_initializer;
535
# define gl_lock_initializer \
537
# define gl_lock_init(NAME) \
538
if (thread_in_use () && mutex_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
539
# define gl_lock_lock(NAME) \
540
if (thread_in_use () && mutex_lock (&NAME) != 0) abort ()
541
# define gl_lock_unlock(NAME) \
542
if (thread_in_use () && mutex_unlock (&NAME) != 0) abort ()
543
# define gl_lock_destroy(NAME) \
544
if (thread_in_use () && mutex_destroy (&NAME) != 0) abort ()
546
/* ------------------------- gl_rwlock_t datatype ------------------------- */
548
typedef rwlock_t gl_rwlock_t;
549
# define gl_rwlock_define(STORAGECLASS, NAME) \
550
STORAGECLASS rwlock_t NAME;
551
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
552
STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
553
# define gl_rwlock_initializer \
555
# define gl_rwlock_init(NAME) \
556
if (thread_in_use () && rwlock_init (&NAME, USYNC_THREAD, NULL) != 0) abort ()
557
# define gl_rwlock_rdlock(NAME) \
558
if (thread_in_use () && rw_rdlock (&NAME) != 0) abort ()
559
# define gl_rwlock_wrlock(NAME) \
560
if (thread_in_use () && rw_wrlock (&NAME) != 0) abort ()
561
# define gl_rwlock_unlock(NAME) \
562
if (thread_in_use () && rw_unlock (&NAME) != 0) abort ()
563
# define gl_rwlock_destroy(NAME) \
564
if (thread_in_use () && rwlock_destroy (&NAME) != 0) abort ()
566
/* --------------------- gl_recursive_lock_t datatype --------------------- */
568
/* Old Solaris threads did not have recursive locks.
569
We have to implement them ourselves. */
578
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
579
STORAGECLASS gl_recursive_lock_t NAME;
580
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
581
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
582
# define gl_recursive_lock_initializer \
583
{ DEFAULTMUTEX, (thread_t) 0, 0 }
584
# define gl_recursive_lock_init(NAME) \
585
if (thread_in_use ()) glthread_recursive_lock_init (&NAME)
586
# define gl_recursive_lock_lock(NAME) \
587
if (thread_in_use ()) glthread_recursive_lock_lock (&NAME)
588
# define gl_recursive_lock_unlock(NAME) \
589
if (thread_in_use ()) glthread_recursive_lock_unlock (&NAME)
590
# define gl_recursive_lock_destroy(NAME) \
591
if (thread_in_use ()) glthread_recursive_lock_destroy (&NAME)
592
extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
593
extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
594
extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
595
extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
597
/* -------------------------- gl_once_t datatype -------------------------- */
605
# define gl_once_define(STORAGECLASS, NAME) \
606
STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
607
# define gl_once(NAME, INITFUNCTION) \
610
if (thread_in_use ()) \
612
glthread_once (&NAME, INITFUNCTION); \
616
if (glthread_once_singlethreaded (&NAME)) \
621
extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
622
extern int glthread_once_singlethreaded (gl_once_t *once_control);
630
/* ========================================================================= */
632
#if USE_WIN32_THREADS
634
# include <windows.h>
640
/* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
641
Semaphore types, because
642
- we need only to synchronize inside a single process (address space),
643
not inter-process locking,
644
- we don't need to support trylock operations. (TryEnterCriticalSection
645
does not work on Windows 95/98/ME. Packages that need trylock usually
646
define their own mutex type.) */
648
/* There is no way to statically initialize a CRITICAL_SECTION. It needs
649
to be done lazily, once only. For this we need spinlocks. */
651
typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
653
/* -------------------------- gl_lock_t datatype -------------------------- */
657
gl_spinlock_t guard; /* protects the initialization */
658
CRITICAL_SECTION lock;
661
# define gl_lock_define(STORAGECLASS, NAME) \
662
STORAGECLASS gl_lock_t NAME;
663
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
664
STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
665
# define gl_lock_initializer \
667
# define gl_lock_init(NAME) \
668
glthread_lock_init (&NAME)
669
# define gl_lock_lock(NAME) \
670
glthread_lock_lock (&NAME)
671
# define gl_lock_unlock(NAME) \
672
glthread_lock_unlock (&NAME)
673
# define gl_lock_destroy(NAME) \
674
glthread_lock_destroy (&NAME)
675
extern void glthread_lock_init (gl_lock_t *lock);
676
extern void glthread_lock_lock (gl_lock_t *lock);
677
extern void glthread_lock_unlock (gl_lock_t *lock);
678
extern void glthread_lock_destroy (gl_lock_t *lock);
680
/* ------------------------- gl_rwlock_t datatype ------------------------- */
682
/* It is impossible to implement read-write locks using plain locks, without
683
introducing an extra thread dedicated to managing read-write locks.
684
Therefore here we need to use the low-level Event type. */
688
HANDLE *array; /* array of waiting threads, each represented by an event */
689
unsigned int count; /* number of waiting threads */
690
unsigned int alloc; /* length of allocated array */
691
unsigned int offset; /* index of first waiting thread in array */
696
gl_spinlock_t guard; /* protects the initialization */
697
CRITICAL_SECTION lock; /* protects the remaining fields */
698
gl_waitqueue_t waiting_readers; /* waiting readers */
699
gl_waitqueue_t waiting_writers; /* waiting writers */
700
int runcount; /* number of readers running, or -1 when a writer runs */
703
# define gl_rwlock_define(STORAGECLASS, NAME) \
704
STORAGECLASS gl_rwlock_t NAME;
705
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
706
STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
707
# define gl_rwlock_initializer \
709
# define gl_rwlock_init(NAME) \
710
glthread_rwlock_init (&NAME)
711
# define gl_rwlock_rdlock(NAME) \
712
glthread_rwlock_rdlock (&NAME)
713
# define gl_rwlock_wrlock(NAME) \
714
glthread_rwlock_wrlock (&NAME)
715
# define gl_rwlock_unlock(NAME) \
716
glthread_rwlock_unlock (&NAME)
717
# define gl_rwlock_destroy(NAME) \
718
glthread_rwlock_destroy (&NAME)
719
extern void glthread_rwlock_init (gl_rwlock_t *lock);
720
extern void glthread_rwlock_rdlock (gl_rwlock_t *lock);
721
extern void glthread_rwlock_wrlock (gl_rwlock_t *lock);
722
extern void glthread_rwlock_unlock (gl_rwlock_t *lock);
723
extern void glthread_rwlock_destroy (gl_rwlock_t *lock);
725
/* --------------------- gl_recursive_lock_t datatype --------------------- */
727
/* The Win32 documentation says that CRITICAL_SECTION already implements a
728
recursive lock. But we need not rely on it: It's easy to implement a
729
recursive lock without this assumption. */
733
gl_spinlock_t guard; /* protects the initialization */
736
CRITICAL_SECTION lock;
739
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
740
STORAGECLASS gl_recursive_lock_t NAME;
741
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
742
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
743
# define gl_recursive_lock_initializer \
745
# define gl_recursive_lock_init(NAME) \
746
glthread_recursive_lock_init (&NAME)
747
# define gl_recursive_lock_lock(NAME) \
748
glthread_recursive_lock_lock (&NAME)
749
# define gl_recursive_lock_unlock(NAME) \
750
glthread_recursive_lock_unlock (&NAME)
751
# define gl_recursive_lock_destroy(NAME) \
752
glthread_recursive_lock_destroy (&NAME)
753
extern void glthread_recursive_lock_init (gl_recursive_lock_t *lock);
754
extern void glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
755
extern void glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
756
extern void glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
758
/* -------------------------- gl_once_t datatype -------------------------- */
763
volatile long started;
764
CRITICAL_SECTION lock;
767
# define gl_once_define(STORAGECLASS, NAME) \
768
STORAGECLASS gl_once_t NAME = { -1, -1 };
769
# define gl_once(NAME, INITFUNCTION) \
770
glthread_once (&NAME, INITFUNCTION)
771
extern void glthread_once (gl_once_t *once_control, void (*initfunction) (void));
779
/* ========================================================================= */
781
#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
783
/* Provide dummy implementation if threads are not supported. */
785
/* -------------------------- gl_lock_t datatype -------------------------- */
787
typedef int gl_lock_t;
788
# define gl_lock_define(STORAGECLASS, NAME)
789
# define gl_lock_define_initialized(STORAGECLASS, NAME)
790
# define gl_lock_init(NAME)
791
# define gl_lock_lock(NAME)
792
# define gl_lock_unlock(NAME)
794
/* ------------------------- gl_rwlock_t datatype ------------------------- */
796
typedef int gl_rwlock_t;
797
# define gl_rwlock_define(STORAGECLASS, NAME)
798
# define gl_rwlock_define_initialized(STORAGECLASS, NAME)
799
# define gl_rwlock_init(NAME)
800
# define gl_rwlock_rdlock(NAME)
801
# define gl_rwlock_wrlock(NAME)
802
# define gl_rwlock_unlock(NAME)
804
/* --------------------- gl_recursive_lock_t datatype --------------------- */
806
typedef int gl_recursive_lock_t;
807
# define gl_recursive_lock_define(STORAGECLASS, NAME)
808
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
809
# define gl_recursive_lock_init(NAME)
810
# define gl_recursive_lock_lock(NAME)
811
# define gl_recursive_lock_unlock(NAME)
813
/* -------------------------- gl_once_t datatype -------------------------- */
815
typedef int gl_once_t;
816
# define gl_once_define(STORAGECLASS, NAME) \
817
STORAGECLASS gl_once_t NAME = 0;
818
# define gl_once(NAME, INITFUNCTION) \
831
/* ========================================================================= */