1
/* Locking in multithreaded situations.
2
Copyright (C) 2005-2013 Free Software Foundation, Inc.
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 3, or (at your option)
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, see <http://www.gnu.org/licenses/>. */
17
/* Written by Bruno Haible <bruno@clisp.org>, 2005.
18
Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
21
/* This file contains locking primitives for use with a given thread library.
22
It does not contain primitives for creating threads or for other
23
synchronization primitives.
25
Normal (non-recursive) locks:
27
Declaration: gl_lock_define(extern, name)
28
Initializer: gl_lock_define_initialized(, name)
29
Initialization: gl_lock_init (name);
30
Taking the lock: gl_lock_lock (name);
31
Releasing the lock: gl_lock_unlock (name);
32
De-initialization: gl_lock_destroy (name);
33
Equivalent functions with control of error handling:
34
Initialization: err = glthread_lock_init (&name);
35
Taking the lock: err = glthread_lock_lock (&name);
36
Releasing the lock: err = glthread_lock_unlock (&name);
37
De-initialization: err = glthread_lock_destroy (&name);
39
Read-Write (non-recursive) locks:
41
Declaration: gl_rwlock_define(extern, name)
42
Initializer: gl_rwlock_define_initialized(, name)
43
Initialization: gl_rwlock_init (name);
44
Taking the lock: gl_rwlock_rdlock (name);
45
gl_rwlock_wrlock (name);
46
Releasing the lock: gl_rwlock_unlock (name);
47
De-initialization: gl_rwlock_destroy (name);
48
Equivalent functions with control of error handling:
49
Initialization: err = glthread_rwlock_init (&name);
50
Taking the lock: err = glthread_rwlock_rdlock (&name);
51
err = glthread_rwlock_wrlock (&name);
52
Releasing the lock: err = glthread_rwlock_unlock (&name);
53
De-initialization: err = glthread_rwlock_destroy (&name);
56
Type: gl_recursive_lock_t
57
Declaration: gl_recursive_lock_define(extern, name)
58
Initializer: gl_recursive_lock_define_initialized(, name)
59
Initialization: gl_recursive_lock_init (name);
60
Taking the lock: gl_recursive_lock_lock (name);
61
Releasing the lock: gl_recursive_lock_unlock (name);
62
De-initialization: gl_recursive_lock_destroy (name);
63
Equivalent functions with control of error handling:
64
Initialization: err = glthread_recursive_lock_init (&name);
65
Taking the lock: err = glthread_recursive_lock_lock (&name);
66
Releasing the lock: err = glthread_recursive_lock_unlock (&name);
67
De-initialization: err = glthread_recursive_lock_destroy (&name);
71
Initializer: gl_once_define(extern, name)
72
Execution: gl_once (name, initfunction);
73
Equivalent functions with control of error handling:
74
Execution: err = glthread_once (&name, initfunction);
84
/* ========================================================================= */
88
/* Use the POSIX threads library. */
96
# if PTHREAD_IN_USE_DETECTION_HARD
98
/* The pthread_in_use() detection needs to be done at runtime. */
99
# define pthread_in_use() \
101
extern int glthread_in_use (void);
105
# if USE_POSIX_THREADS_WEAK
107
/* Use weak references to the POSIX threads library. */
109
/* Weak references avoid dragging in external libraries if the other parts
110
of the program don't use them. Here we use them, because we don't want
111
every program that uses libintl to depend on libpthread. This assumes
112
that libpthread would not be loaded after libintl; i.e. if libintl is
113
loaded first, by an executable that does not depend on libpthread, and
114
then a module is dynamically loaded that depends on libpthread, libintl
115
will not be multithread-safe. */
117
/* The way to test at runtime whether libpthread is present is to test
118
whether a function pointer's value, such as &pthread_mutex_init, is
119
non-NULL. However, some versions of GCC have a bug through which, in
120
PIC mode, &foo != NULL always evaluates to true if there is a direct
121
call to foo(...) in the same function. To avoid this, we test the
122
address of a function in libpthread that we don't use. */
124
# pragma weak pthread_mutex_init
125
# pragma weak pthread_mutex_lock
126
# pragma weak pthread_mutex_unlock
127
# pragma weak pthread_mutex_destroy
128
# pragma weak pthread_rwlock_init
129
# pragma weak pthread_rwlock_rdlock
130
# pragma weak pthread_rwlock_wrlock
131
# pragma weak pthread_rwlock_unlock
132
# pragma weak pthread_rwlock_destroy
133
# pragma weak pthread_once
134
# pragma weak pthread_cond_init
135
# pragma weak pthread_cond_wait
136
# pragma weak pthread_cond_signal
137
# pragma weak pthread_cond_broadcast
138
# pragma weak pthread_cond_destroy
139
# pragma weak pthread_mutexattr_init
140
# pragma weak pthread_mutexattr_settype
141
# pragma weak pthread_mutexattr_destroy
142
# ifndef pthread_self
143
# pragma weak pthread_self
146
# if !PTHREAD_IN_USE_DETECTION_HARD
147
# pragma weak pthread_cancel
148
# define pthread_in_use() (pthread_cancel != NULL)
153
# if !PTHREAD_IN_USE_DETECTION_HARD
154
# define pthread_in_use() 1
159
/* -------------------------- gl_lock_t datatype -------------------------- */
161
typedef pthread_mutex_t gl_lock_t;
162
# define gl_lock_define(STORAGECLASS, NAME) \
163
STORAGECLASS pthread_mutex_t NAME;
164
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
165
STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
166
# define gl_lock_initializer \
167
PTHREAD_MUTEX_INITIALIZER
168
# define glthread_lock_init(LOCK) \
169
(pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
170
# define glthread_lock_lock(LOCK) \
171
(pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
172
# define glthread_lock_unlock(LOCK) \
173
(pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
174
# define glthread_lock_destroy(LOCK) \
175
(pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
177
/* ------------------------- gl_rwlock_t datatype ------------------------- */
179
# if HAVE_PTHREAD_RWLOCK
181
# ifdef PTHREAD_RWLOCK_INITIALIZER
183
typedef pthread_rwlock_t gl_rwlock_t;
184
# define gl_rwlock_define(STORAGECLASS, NAME) \
185
STORAGECLASS pthread_rwlock_t NAME;
186
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
187
STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
188
# define gl_rwlock_initializer \
189
PTHREAD_RWLOCK_INITIALIZER
190
# define glthread_rwlock_init(LOCK) \
191
(pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
192
# define glthread_rwlock_rdlock(LOCK) \
193
(pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
194
# define glthread_rwlock_wrlock(LOCK) \
195
(pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
196
# define glthread_rwlock_unlock(LOCK) \
197
(pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
198
# define glthread_rwlock_destroy(LOCK) \
199
(pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
206
pthread_mutex_t guard; /* protects the initialization */
207
pthread_rwlock_t rwlock; /* read-write lock */
210
# define gl_rwlock_define(STORAGECLASS, NAME) \
211
STORAGECLASS gl_rwlock_t NAME;
212
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
213
STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
214
# define gl_rwlock_initializer \
215
{ 0, PTHREAD_MUTEX_INITIALIZER }
216
# define glthread_rwlock_init(LOCK) \
217
(pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
218
# define glthread_rwlock_rdlock(LOCK) \
219
(pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
220
# define glthread_rwlock_wrlock(LOCK) \
221
(pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
222
# define glthread_rwlock_unlock(LOCK) \
223
(pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
224
# define glthread_rwlock_destroy(LOCK) \
225
(pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
226
extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
227
extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
228
extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
229
extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
230
extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
238
pthread_mutex_t lock; /* protects the remaining fields */
239
pthread_cond_t waiting_readers; /* waiting readers */
240
pthread_cond_t waiting_writers; /* waiting writers */
241
unsigned int waiting_writers_count; /* number of waiting writers */
242
int runcount; /* number of readers running, or -1 when a writer runs */
245
# define gl_rwlock_define(STORAGECLASS, NAME) \
246
STORAGECLASS gl_rwlock_t NAME;
247
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
248
STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
249
# define gl_rwlock_initializer \
250
{ PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
251
# define glthread_rwlock_init(LOCK) \
252
(pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
253
# define glthread_rwlock_rdlock(LOCK) \
254
(pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
255
# define glthread_rwlock_wrlock(LOCK) \
256
(pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
257
# define glthread_rwlock_unlock(LOCK) \
258
(pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
259
# define glthread_rwlock_destroy(LOCK) \
260
(pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
261
extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
262
extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
263
extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
264
extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
265
extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
269
/* --------------------- gl_recursive_lock_t datatype --------------------- */
271
# if HAVE_PTHREAD_MUTEX_RECURSIVE
273
# if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
275
typedef pthread_mutex_t gl_recursive_lock_t;
276
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
277
STORAGECLASS pthread_mutex_t NAME;
278
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
279
STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
280
# ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
281
# define gl_recursive_lock_initializer \
282
PTHREAD_RECURSIVE_MUTEX_INITIALIZER
284
# define gl_recursive_lock_initializer \
285
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
287
# define glthread_recursive_lock_init(LOCK) \
288
(pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
289
# define glthread_recursive_lock_lock(LOCK) \
290
(pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
291
# define glthread_recursive_lock_unlock(LOCK) \
292
(pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
293
# define glthread_recursive_lock_destroy(LOCK) \
294
(pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
295
extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
301
pthread_mutex_t recmutex; /* recursive mutex */
302
pthread_mutex_t guard; /* protects the initialization */
306
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
307
STORAGECLASS gl_recursive_lock_t NAME;
308
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
309
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
310
# define gl_recursive_lock_initializer \
311
{ PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
312
# define glthread_recursive_lock_init(LOCK) \
313
(pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
314
# define glthread_recursive_lock_lock(LOCK) \
315
(pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
316
# define glthread_recursive_lock_unlock(LOCK) \
317
(pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
318
# define glthread_recursive_lock_destroy(LOCK) \
319
(pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
320
extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
321
extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
322
extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
323
extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
329
/* Old versions of POSIX threads on Solaris did not have recursive locks.
330
We have to implement them ourselves. */
334
pthread_mutex_t mutex;
339
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
340
STORAGECLASS gl_recursive_lock_t NAME;
341
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
342
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
343
# define gl_recursive_lock_initializer \
344
{ PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
345
# define glthread_recursive_lock_init(LOCK) \
346
(pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
347
# define glthread_recursive_lock_lock(LOCK) \
348
(pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
349
# define glthread_recursive_lock_unlock(LOCK) \
350
(pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
351
# define glthread_recursive_lock_destroy(LOCK) \
352
(pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
353
extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
354
extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
355
extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
356
extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
360
/* -------------------------- gl_once_t datatype -------------------------- */
362
typedef pthread_once_t gl_once_t;
363
# define gl_once_define(STORAGECLASS, NAME) \
364
STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
365
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
367
? pthread_once (ONCE_CONTROL, INITFUNCTION) \
368
: (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
369
extern int glthread_once_singlethreaded (pthread_once_t *once_control);
377
/* ========================================================================= */
381
/* Use the GNU Pth threads library. */
389
# if USE_PTH_THREADS_WEAK
391
/* Use weak references to the GNU Pth threads library. */
393
# pragma weak pth_mutex_init
394
# pragma weak pth_mutex_acquire
395
# pragma weak pth_mutex_release
396
# pragma weak pth_rwlock_init
397
# pragma weak pth_rwlock_acquire
398
# pragma weak pth_rwlock_release
399
# pragma weak pth_once
401
# pragma weak pth_cancel
402
# define pth_in_use() (pth_cancel != NULL)
406
# define pth_in_use() 1
410
/* -------------------------- gl_lock_t datatype -------------------------- */
412
typedef pth_mutex_t gl_lock_t;
413
# define gl_lock_define(STORAGECLASS, NAME) \
414
STORAGECLASS pth_mutex_t NAME;
415
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
416
STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
417
# define gl_lock_initializer \
419
# define glthread_lock_init(LOCK) \
420
(pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
421
# define glthread_lock_lock(LOCK) \
422
(pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
423
# define glthread_lock_unlock(LOCK) \
424
(pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
425
# define glthread_lock_destroy(LOCK) \
428
/* ------------------------- gl_rwlock_t datatype ------------------------- */
430
typedef pth_rwlock_t gl_rwlock_t;
431
# define gl_rwlock_define(STORAGECLASS, NAME) \
432
STORAGECLASS pth_rwlock_t NAME;
433
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
434
STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
435
# define gl_rwlock_initializer \
437
# define glthread_rwlock_init(LOCK) \
438
(pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0)
439
# define glthread_rwlock_rdlock(LOCK) \
440
(pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0)
441
# define glthread_rwlock_wrlock(LOCK) \
442
(pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0)
443
# define glthread_rwlock_unlock(LOCK) \
444
(pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0)
445
# define glthread_rwlock_destroy(LOCK) \
448
/* --------------------- gl_recursive_lock_t datatype --------------------- */
450
/* In Pth, mutexes are recursive by default. */
451
typedef pth_mutex_t gl_recursive_lock_t;
452
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
453
STORAGECLASS pth_mutex_t NAME;
454
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
455
STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
456
# define gl_recursive_lock_initializer \
458
# define glthread_recursive_lock_init(LOCK) \
459
(pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
460
# define glthread_recursive_lock_lock(LOCK) \
461
(pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
462
# define glthread_recursive_lock_unlock(LOCK) \
463
(pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
464
# define glthread_recursive_lock_destroy(LOCK) \
467
/* -------------------------- gl_once_t datatype -------------------------- */
469
typedef pth_once_t gl_once_t;
470
# define gl_once_define(STORAGECLASS, NAME) \
471
STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
472
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
474
? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
475
: (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
476
extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void));
477
extern int glthread_once_singlethreaded (pth_once_t *once_control);
485
/* ========================================================================= */
487
#if USE_SOLARIS_THREADS
489
/* Use the old Solaris threads library. */
498
# if USE_SOLARIS_THREADS_WEAK
500
/* Use weak references to the old Solaris threads library. */
502
# pragma weak mutex_init
503
# pragma weak mutex_lock
504
# pragma weak mutex_unlock
505
# pragma weak mutex_destroy
506
# pragma weak rwlock_init
507
# pragma weak rw_rdlock
508
# pragma weak rw_wrlock
509
# pragma weak rw_unlock
510
# pragma weak rwlock_destroy
511
# pragma weak thr_self
513
# pragma weak thr_suspend
514
# define thread_in_use() (thr_suspend != NULL)
518
# define thread_in_use() 1
522
/* -------------------------- gl_lock_t datatype -------------------------- */
524
typedef mutex_t gl_lock_t;
525
# define gl_lock_define(STORAGECLASS, NAME) \
526
STORAGECLASS mutex_t NAME;
527
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
528
STORAGECLASS mutex_t NAME = gl_lock_initializer;
529
# define gl_lock_initializer \
531
# define glthread_lock_init(LOCK) \
532
(thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
533
# define glthread_lock_lock(LOCK) \
534
(thread_in_use () ? mutex_lock (LOCK) : 0)
535
# define glthread_lock_unlock(LOCK) \
536
(thread_in_use () ? mutex_unlock (LOCK) : 0)
537
# define glthread_lock_destroy(LOCK) \
538
(thread_in_use () ? mutex_destroy (LOCK) : 0)
540
/* ------------------------- gl_rwlock_t datatype ------------------------- */
542
typedef rwlock_t gl_rwlock_t;
543
# define gl_rwlock_define(STORAGECLASS, NAME) \
544
STORAGECLASS rwlock_t NAME;
545
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
546
STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
547
# define gl_rwlock_initializer \
549
# define glthread_rwlock_init(LOCK) \
550
(thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
551
# define glthread_rwlock_rdlock(LOCK) \
552
(thread_in_use () ? rw_rdlock (LOCK) : 0)
553
# define glthread_rwlock_wrlock(LOCK) \
554
(thread_in_use () ? rw_wrlock (LOCK) : 0)
555
# define glthread_rwlock_unlock(LOCK) \
556
(thread_in_use () ? rw_unlock (LOCK) : 0)
557
# define glthread_rwlock_destroy(LOCK) \
558
(thread_in_use () ? rwlock_destroy (LOCK) : 0)
560
/* --------------------- gl_recursive_lock_t datatype --------------------- */
562
/* Old Solaris threads did not have recursive locks.
563
We have to implement them ourselves. */
572
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
573
STORAGECLASS gl_recursive_lock_t NAME;
574
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
575
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
576
# define gl_recursive_lock_initializer \
577
{ DEFAULTMUTEX, (thread_t) 0, 0 }
578
# define glthread_recursive_lock_init(LOCK) \
579
(thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
580
# define glthread_recursive_lock_lock(LOCK) \
581
(thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
582
# define glthread_recursive_lock_unlock(LOCK) \
583
(thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
584
# define glthread_recursive_lock_destroy(LOCK) \
585
(thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
586
extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
587
extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
588
extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
589
extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
591
/* -------------------------- gl_once_t datatype -------------------------- */
599
# define gl_once_define(STORAGECLASS, NAME) \
600
STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
601
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
603
? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
604
: (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
605
extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
606
extern int glthread_once_singlethreaded (gl_once_t *once_control);
614
/* ========================================================================= */
616
#if USE_WINDOWS_THREADS
618
# define WIN32_LEAN_AND_MEAN /* avoid including junk */
619
# include <windows.h>
625
/* We can use CRITICAL_SECTION directly, rather than the native Windows Event,
626
Mutex, Semaphore types, because
627
- we need only to synchronize inside a single process (address space),
628
not inter-process locking,
629
- we don't need to support trylock operations. (TryEnterCriticalSection
630
does not work on Windows 95/98/ME. Packages that need trylock usually
631
define their own mutex type.) */
633
/* There is no way to statically initialize a CRITICAL_SECTION. It needs
634
to be done lazily, once only. For this we need spinlocks. */
636
typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
638
/* -------------------------- gl_lock_t datatype -------------------------- */
642
gl_spinlock_t guard; /* protects the initialization */
643
CRITICAL_SECTION lock;
646
# define gl_lock_define(STORAGECLASS, NAME) \
647
STORAGECLASS gl_lock_t NAME;
648
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
649
STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
650
# define gl_lock_initializer \
652
# define glthread_lock_init(LOCK) \
653
(glthread_lock_init_func (LOCK), 0)
654
# define glthread_lock_lock(LOCK) \
655
glthread_lock_lock_func (LOCK)
656
# define glthread_lock_unlock(LOCK) \
657
glthread_lock_unlock_func (LOCK)
658
# define glthread_lock_destroy(LOCK) \
659
glthread_lock_destroy_func (LOCK)
660
extern void glthread_lock_init_func (gl_lock_t *lock);
661
extern int glthread_lock_lock_func (gl_lock_t *lock);
662
extern int glthread_lock_unlock_func (gl_lock_t *lock);
663
extern int glthread_lock_destroy_func (gl_lock_t *lock);
665
/* ------------------------- gl_rwlock_t datatype ------------------------- */
667
/* It is impossible to implement read-write locks using plain locks, without
668
introducing an extra thread dedicated to managing read-write locks.
669
Therefore here we need to use the low-level Event type. */
673
HANDLE *array; /* array of waiting threads, each represented by an event */
674
unsigned int count; /* number of waiting threads */
675
unsigned int alloc; /* length of allocated array */
676
unsigned int offset; /* index of first waiting thread in array */
678
gl_carray_waitqueue_t;
681
gl_spinlock_t guard; /* protects the initialization */
682
CRITICAL_SECTION lock; /* protects the remaining fields */
683
gl_carray_waitqueue_t waiting_readers; /* waiting readers */
684
gl_carray_waitqueue_t waiting_writers; /* waiting writers */
685
int runcount; /* number of readers running, or -1 when a writer runs */
688
# define gl_rwlock_define(STORAGECLASS, NAME) \
689
STORAGECLASS gl_rwlock_t NAME;
690
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
691
STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
692
# define gl_rwlock_initializer \
694
# define glthread_rwlock_init(LOCK) \
695
(glthread_rwlock_init_func (LOCK), 0)
696
# define glthread_rwlock_rdlock(LOCK) \
697
glthread_rwlock_rdlock_func (LOCK)
698
# define glthread_rwlock_wrlock(LOCK) \
699
glthread_rwlock_wrlock_func (LOCK)
700
# define glthread_rwlock_unlock(LOCK) \
701
glthread_rwlock_unlock_func (LOCK)
702
# define glthread_rwlock_destroy(LOCK) \
703
glthread_rwlock_destroy_func (LOCK)
704
extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
705
extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock);
706
extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock);
707
extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock);
708
extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock);
710
/* --------------------- gl_recursive_lock_t datatype --------------------- */
712
/* The native Windows documentation says that CRITICAL_SECTION already
713
implements a recursive lock. But we need not rely on it: It's easy to
714
implement a recursive lock without this assumption. */
718
gl_spinlock_t guard; /* protects the initialization */
721
CRITICAL_SECTION lock;
724
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
725
STORAGECLASS gl_recursive_lock_t NAME;
726
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
727
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
728
# define gl_recursive_lock_initializer \
730
# define glthread_recursive_lock_init(LOCK) \
731
(glthread_recursive_lock_init_func (LOCK), 0)
732
# define glthread_recursive_lock_lock(LOCK) \
733
glthread_recursive_lock_lock_func (LOCK)
734
# define glthread_recursive_lock_unlock(LOCK) \
735
glthread_recursive_lock_unlock_func (LOCK)
736
# define glthread_recursive_lock_destroy(LOCK) \
737
glthread_recursive_lock_destroy_func (LOCK)
738
extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
739
extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock);
740
extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock);
741
extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock);
743
/* -------------------------- gl_once_t datatype -------------------------- */
748
volatile long started;
749
CRITICAL_SECTION lock;
752
# define gl_once_define(STORAGECLASS, NAME) \
753
STORAGECLASS gl_once_t NAME = { -1, -1 };
754
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
755
(glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
756
extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
764
/* ========================================================================= */
766
#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
768
/* Provide dummy implementation if threads are not supported. */
770
/* -------------------------- gl_lock_t datatype -------------------------- */
772
typedef int gl_lock_t;
773
# define gl_lock_define(STORAGECLASS, NAME)
774
# define gl_lock_define_initialized(STORAGECLASS, NAME)
775
# define glthread_lock_init(NAME) 0
776
# define glthread_lock_lock(NAME) 0
777
# define glthread_lock_unlock(NAME) 0
778
# define glthread_lock_destroy(NAME) 0
780
/* ------------------------- gl_rwlock_t datatype ------------------------- */
782
typedef int gl_rwlock_t;
783
# define gl_rwlock_define(STORAGECLASS, NAME)
784
# define gl_rwlock_define_initialized(STORAGECLASS, NAME)
785
# define glthread_rwlock_init(NAME) 0
786
# define glthread_rwlock_rdlock(NAME) 0
787
# define glthread_rwlock_wrlock(NAME) 0
788
# define glthread_rwlock_unlock(NAME) 0
789
# define glthread_rwlock_destroy(NAME) 0
791
/* --------------------- gl_recursive_lock_t datatype --------------------- */
793
typedef int gl_recursive_lock_t;
794
# define gl_recursive_lock_define(STORAGECLASS, NAME)
795
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
796
# define glthread_recursive_lock_init(NAME) 0
797
# define glthread_recursive_lock_lock(NAME) 0
798
# define glthread_recursive_lock_unlock(NAME) 0
799
# define glthread_recursive_lock_destroy(NAME) 0
801
/* -------------------------- gl_once_t datatype -------------------------- */
803
typedef int gl_once_t;
804
# define gl_once_define(STORAGECLASS, NAME) \
805
STORAGECLASS gl_once_t NAME = 0;
806
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
807
(*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
811
/* ========================================================================= */
813
/* Macros with built-in error handling. */
815
/* -------------------------- gl_lock_t datatype -------------------------- */
817
#define gl_lock_init(NAME) \
820
if (glthread_lock_init (&NAME)) \
824
#define gl_lock_lock(NAME) \
827
if (glthread_lock_lock (&NAME)) \
831
#define gl_lock_unlock(NAME) \
834
if (glthread_lock_unlock (&NAME)) \
838
#define gl_lock_destroy(NAME) \
841
if (glthread_lock_destroy (&NAME)) \
846
/* ------------------------- gl_rwlock_t datatype ------------------------- */
848
#define gl_rwlock_init(NAME) \
851
if (glthread_rwlock_init (&NAME)) \
855
#define gl_rwlock_rdlock(NAME) \
858
if (glthread_rwlock_rdlock (&NAME)) \
862
#define gl_rwlock_wrlock(NAME) \
865
if (glthread_rwlock_wrlock (&NAME)) \
869
#define gl_rwlock_unlock(NAME) \
872
if (glthread_rwlock_unlock (&NAME)) \
876
#define gl_rwlock_destroy(NAME) \
879
if (glthread_rwlock_destroy (&NAME)) \
884
/* --------------------- gl_recursive_lock_t datatype --------------------- */
886
#define gl_recursive_lock_init(NAME) \
889
if (glthread_recursive_lock_init (&NAME)) \
893
#define gl_recursive_lock_lock(NAME) \
896
if (glthread_recursive_lock_lock (&NAME)) \
900
#define gl_recursive_lock_unlock(NAME) \
903
if (glthread_recursive_lock_unlock (&NAME)) \
907
#define gl_recursive_lock_destroy(NAME) \
910
if (glthread_recursive_lock_destroy (&NAME)) \
915
/* -------------------------- gl_once_t datatype -------------------------- */
917
#define gl_once(NAME, INITFUNCTION) \
920
if (glthread_once (&NAME, INITFUNCTION)) \
925
/* ========================================================================= */