]> git.deb.at Git - pkg/abook.git/blob - intl/lock.h
autotools update: 1/2: main files
[pkg/abook.git] / intl / lock.h
1 /* Locking in multithreaded situations.
2    Copyright (C) 2005-2008 Free Software Foundation, Inc.
3
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)
7    any later version.
8
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.
13
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,
17    USA.  */
18
19 /* Written by Bruno Haible <bruno@clisp.org>, 2005.
20    Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
21    gthr-win32.h.  */
22
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.
26
27    Normal (non-recursive) locks:
28      Type:                gl_lock_t
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);
35    Equivalent functions with control of error handling:
36      Initialization:      err = glthread_lock_init (&name);
37      Taking the lock:     err = glthread_lock_lock (&name);
38      Releasing the lock:  err = glthread_lock_unlock (&name);
39      De-initialization:   err = glthread_lock_destroy (&name);
40
41    Read-Write (non-recursive) locks:
42      Type:                gl_rwlock_t
43      Declaration:         gl_rwlock_define(extern, name)
44      Initializer:         gl_rwlock_define_initialized(, name)
45      Initialization:      gl_rwlock_init (name);
46      Taking the lock:     gl_rwlock_rdlock (name);
47                           gl_rwlock_wrlock (name);
48      Releasing the lock:  gl_rwlock_unlock (name);
49      De-initialization:   gl_rwlock_destroy (name);
50    Equivalent functions with control of error handling:
51      Initialization:      err = glthread_rwlock_init (&name);
52      Taking the lock:     err = glthread_rwlock_rdlock (&name);
53                           err = glthread_rwlock_wrlock (&name);
54      Releasing the lock:  err = glthread_rwlock_unlock (&name);
55      De-initialization:   err = glthread_rwlock_destroy (&name);
56
57    Recursive locks:
58      Type:                gl_recursive_lock_t
59      Declaration:         gl_recursive_lock_define(extern, name)
60      Initializer:         gl_recursive_lock_define_initialized(, name)
61      Initialization:      gl_recursive_lock_init (name);
62      Taking the lock:     gl_recursive_lock_lock (name);
63      Releasing the lock:  gl_recursive_lock_unlock (name);
64      De-initialization:   gl_recursive_lock_destroy (name);
65    Equivalent functions with control of error handling:
66      Initialization:      err = glthread_recursive_lock_init (&name);
67      Taking the lock:     err = glthread_recursive_lock_lock (&name);
68      Releasing the lock:  err = glthread_recursive_lock_unlock (&name);
69      De-initialization:   err = glthread_recursive_lock_destroy (&name);
70
71   Once-only execution:
72      Type:                gl_once_t
73      Initializer:         gl_once_define(extern, name)
74      Execution:           gl_once (name, initfunction);
75    Equivalent functions with control of error handling:
76      Execution:           err = glthread_once (&name, initfunction);
77 */
78
79
80 #ifndef _LOCK_H
81 #define _LOCK_H
82
83 #include <errno.h>
84 #include <stdlib.h>
85
86 /* ========================================================================= */
87
88 #if USE_POSIX_THREADS
89
90 /* Use the POSIX threads library.  */
91
92 # include <pthread.h>
93
94 # ifdef __cplusplus
95 extern "C" {
96 # endif
97
98 # if PTHREAD_IN_USE_DETECTION_HARD
99
100 /* The pthread_in_use() detection needs to be done at runtime.  */
101 #  define pthread_in_use() \
102      glthread_in_use ()
103 extern int glthread_in_use (void);
104
105 # endif
106
107 # if USE_POSIX_THREADS_WEAK
108
109 /* Use weak references to the POSIX threads library.  */
110
111 /* Weak references avoid dragging in external libraries if the other parts
112    of the program don't use them.  Here we use them, because we don't want
113    every program that uses libintl to depend on libpthread.  This assumes
114    that libpthread would not be loaded after libintl; i.e. if libintl is
115    loaded first, by an executable that does not depend on libpthread, and
116    then a module is dynamically loaded that depends on libpthread, libintl
117    will not be multithread-safe.  */
118
119 /* The way to test at runtime whether libpthread is present is to test
120    whether a function pointer's value, such as &pthread_mutex_init, is
121    non-NULL.  However, some versions of GCC have a bug through which, in
122    PIC mode, &foo != NULL always evaluates to true if there is a direct
123    call to foo(...) in the same function.  To avoid this, we test the
124    address of a function in libpthread that we don't use.  */
125
126 #  pragma weak pthread_mutex_init
127 #  pragma weak pthread_mutex_lock
128 #  pragma weak pthread_mutex_unlock
129 #  pragma weak pthread_mutex_destroy
130 #  pragma weak pthread_rwlock_init
131 #  pragma weak pthread_rwlock_rdlock
132 #  pragma weak pthread_rwlock_wrlock
133 #  pragma weak pthread_rwlock_unlock
134 #  pragma weak pthread_rwlock_destroy
135 #  pragma weak pthread_once
136 #  pragma weak pthread_cond_init
137 #  pragma weak pthread_cond_wait
138 #  pragma weak pthread_cond_signal
139 #  pragma weak pthread_cond_broadcast
140 #  pragma weak pthread_cond_destroy
141 #  pragma weak pthread_mutexattr_init
142 #  pragma weak pthread_mutexattr_settype
143 #  pragma weak pthread_mutexattr_destroy
144 #  ifndef pthread_self
145 #   pragma weak pthread_self
146 #  endif
147
148 #  if !PTHREAD_IN_USE_DETECTION_HARD
149 #   pragma weak pthread_cancel
150 #   define pthread_in_use() (pthread_cancel != NULL)
151 #  endif
152
153 # else
154
155 #  if !PTHREAD_IN_USE_DETECTION_HARD
156 #   define pthread_in_use() 1
157 #  endif
158
159 # endif
160
161 /* -------------------------- gl_lock_t datatype -------------------------- */
162
163 typedef pthread_mutex_t gl_lock_t;
164 # define gl_lock_define(STORAGECLASS, NAME) \
165     STORAGECLASS pthread_mutex_t NAME;
166 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
167     STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
168 # define gl_lock_initializer \
169     PTHREAD_MUTEX_INITIALIZER
170 # define glthread_lock_init(LOCK) \
171     (pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
172 # define glthread_lock_lock(LOCK) \
173     (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
174 # define glthread_lock_unlock(LOCK) \
175     (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
176 # define glthread_lock_destroy(LOCK) \
177     (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
178
179 /* ------------------------- gl_rwlock_t datatype ------------------------- */
180
181 # if HAVE_PTHREAD_RWLOCK
182
183 #  ifdef PTHREAD_RWLOCK_INITIALIZER
184
185 typedef pthread_rwlock_t gl_rwlock_t;
186 #   define gl_rwlock_define(STORAGECLASS, NAME) \
187       STORAGECLASS pthread_rwlock_t NAME;
188 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
189       STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
190 #   define gl_rwlock_initializer \
191       PTHREAD_RWLOCK_INITIALIZER
192 #   define glthread_rwlock_init(LOCK) \
193       (pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
194 #   define glthread_rwlock_rdlock(LOCK) \
195       (pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
196 #   define glthread_rwlock_wrlock(LOCK) \
197       (pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
198 #   define glthread_rwlock_unlock(LOCK) \
199       (pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
200 #   define glthread_rwlock_destroy(LOCK) \
201       (pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
202
203 #  else
204
205 typedef struct
206         {
207           int initialized;
208           pthread_mutex_t guard;   /* protects the initialization */
209           pthread_rwlock_t rwlock; /* read-write lock */
210         }
211         gl_rwlock_t;
212 #   define gl_rwlock_define(STORAGECLASS, NAME) \
213       STORAGECLASS gl_rwlock_t NAME;
214 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
215       STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
216 #   define gl_rwlock_initializer \
217       { 0, PTHREAD_MUTEX_INITIALIZER }
218 #   define glthread_rwlock_init(LOCK) \
219       (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
220 #   define glthread_rwlock_rdlock(LOCK) \
221       (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
222 #   define glthread_rwlock_wrlock(LOCK) \
223       (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
224 #   define glthread_rwlock_unlock(LOCK) \
225       (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
226 #   define glthread_rwlock_destroy(LOCK) \
227       (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
228 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
229 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
230 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
231 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
232 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
233
234 #  endif
235
236 # else
237
238 typedef struct
239         {
240           pthread_mutex_t lock; /* protects the remaining fields */
241           pthread_cond_t waiting_readers; /* waiting readers */
242           pthread_cond_t waiting_writers; /* waiting writers */
243           unsigned int waiting_writers_count; /* number of waiting writers */
244           int runcount; /* number of readers running, or -1 when a writer runs */
245         }
246         gl_rwlock_t;
247 # define gl_rwlock_define(STORAGECLASS, NAME) \
248     STORAGECLASS gl_rwlock_t NAME;
249 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
250     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
251 # define gl_rwlock_initializer \
252     { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
253 # define glthread_rwlock_init(LOCK) \
254     (pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
255 # define glthread_rwlock_rdlock(LOCK) \
256     (pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
257 # define glthread_rwlock_wrlock(LOCK) \
258     (pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
259 # define glthread_rwlock_unlock(LOCK) \
260     (pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
261 # define glthread_rwlock_destroy(LOCK) \
262     (pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
263 extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
264 extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
265 extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
266 extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
267 extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
268
269 # endif
270
271 /* --------------------- gl_recursive_lock_t datatype --------------------- */
272
273 # if HAVE_PTHREAD_MUTEX_RECURSIVE
274
275 #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
276
277 typedef pthread_mutex_t gl_recursive_lock_t;
278 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
279       STORAGECLASS pthread_mutex_t NAME;
280 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
281       STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
282 #   ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
283 #    define gl_recursive_lock_initializer \
284        PTHREAD_RECURSIVE_MUTEX_INITIALIZER
285 #   else
286 #    define gl_recursive_lock_initializer \
287        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
288 #   endif
289 #   define glthread_recursive_lock_init(LOCK) \
290       (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
291 #   define glthread_recursive_lock_lock(LOCK) \
292       (pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
293 #   define glthread_recursive_lock_unlock(LOCK) \
294       (pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
295 #   define glthread_recursive_lock_destroy(LOCK) \
296       (pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
297 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
298
299 #  else
300
301 typedef struct
302         {
303           pthread_mutex_t recmutex; /* recursive mutex */
304           pthread_mutex_t guard;    /* protects the initialization */
305           int initialized;
306         }
307         gl_recursive_lock_t;
308 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
309       STORAGECLASS gl_recursive_lock_t NAME;
310 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
311       STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
312 #   define gl_recursive_lock_initializer \
313       { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
314 #   define glthread_recursive_lock_init(LOCK) \
315       (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
316 #   define glthread_recursive_lock_lock(LOCK) \
317       (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
318 #   define glthread_recursive_lock_unlock(LOCK) \
319       (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
320 #   define glthread_recursive_lock_destroy(LOCK) \
321       (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
322 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
323 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
324 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
325 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
326
327 #  endif
328
329 # else
330
331 /* Old versions of POSIX threads on Solaris did not have recursive locks.
332    We have to implement them ourselves.  */
333
334 typedef struct
335         {
336           pthread_mutex_t mutex;
337           pthread_t owner;
338           unsigned long depth;
339         }
340         gl_recursive_lock_t;
341 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
342      STORAGECLASS gl_recursive_lock_t NAME;
343 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
344      STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
345 #  define gl_recursive_lock_initializer \
346      { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
347 #  define glthread_recursive_lock_init(LOCK) \
348      (pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
349 #  define glthread_recursive_lock_lock(LOCK) \
350      (pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
351 #  define glthread_recursive_lock_unlock(LOCK) \
352      (pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
353 #  define glthread_recursive_lock_destroy(LOCK) \
354      (pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
355 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
356 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
357 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
358 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
359
360 # endif
361
362 /* -------------------------- gl_once_t datatype -------------------------- */
363
364 typedef pthread_once_t gl_once_t;
365 # define gl_once_define(STORAGECLASS, NAME) \
366     STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
367 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
368     (pthread_in_use ()                                                         \
369      ? pthread_once (ONCE_CONTROL, INITFUNCTION)                               \
370      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
371 extern int glthread_once_singlethreaded (pthread_once_t *once_control);
372
373 # ifdef __cplusplus
374 }
375 # endif
376
377 #endif
378
379 /* ========================================================================= */
380
381 #if USE_PTH_THREADS
382
383 /* Use the GNU Pth threads library.  */
384
385 # include <pth.h>
386
387 # ifdef __cplusplus
388 extern "C" {
389 # endif
390
391 # if USE_PTH_THREADS_WEAK
392
393 /* Use weak references to the GNU Pth threads library.  */
394
395 #  pragma weak pth_mutex_init
396 #  pragma weak pth_mutex_acquire
397 #  pragma weak pth_mutex_release
398 #  pragma weak pth_rwlock_init
399 #  pragma weak pth_rwlock_acquire
400 #  pragma weak pth_rwlock_release
401 #  pragma weak pth_once
402
403 #  pragma weak pth_cancel
404 #  define pth_in_use() (pth_cancel != NULL)
405
406 # else
407
408 #  define pth_in_use() 1
409
410 # endif
411
412 /* -------------------------- gl_lock_t datatype -------------------------- */
413
414 typedef pth_mutex_t gl_lock_t;
415 # define gl_lock_define(STORAGECLASS, NAME) \
416     STORAGECLASS pth_mutex_t NAME;
417 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
418     STORAGECLASS pth_mutex_t NAME = gl_lock_initializer;
419 # define gl_lock_initializer \
420     PTH_MUTEX_INIT
421 # define glthread_lock_init(LOCK) \
422     (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
423 # define glthread_lock_lock(LOCK) \
424     (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
425 # define glthread_lock_unlock(LOCK) \
426     (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
427 # define glthread_lock_destroy(LOCK) \
428     ((void)(LOCK), 0)
429
430 /* ------------------------- gl_rwlock_t datatype ------------------------- */
431
432 typedef pth_rwlock_t gl_rwlock_t;
433 #  define gl_rwlock_define(STORAGECLASS, NAME) \
434      STORAGECLASS pth_rwlock_t NAME;
435 #  define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
436      STORAGECLASS pth_rwlock_t NAME = gl_rwlock_initializer;
437 #  define gl_rwlock_initializer \
438      PTH_RWLOCK_INIT
439 #  define glthread_rwlock_init(LOCK) \
440      (pth_in_use () && !pth_rwlock_init (LOCK) ? errno : 0)
441 #  define glthread_rwlock_rdlock(LOCK) \
442      (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RD, 0, NULL) ? errno : 0)
443 #  define glthread_rwlock_wrlock(LOCK) \
444      (pth_in_use () && !pth_rwlock_acquire (LOCK, PTH_RWLOCK_RW, 0, NULL) ? errno : 0)
445 #  define glthread_rwlock_unlock(LOCK) \
446      (pth_in_use () && !pth_rwlock_release (LOCK) ? errno : 0)
447 #  define glthread_rwlock_destroy(LOCK) \
448      ((void)(LOCK), 0)
449
450 /* --------------------- gl_recursive_lock_t datatype --------------------- */
451
452 /* In Pth, mutexes are recursive by default.  */
453 typedef pth_mutex_t gl_recursive_lock_t;
454 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
455      STORAGECLASS pth_mutex_t NAME;
456 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
457      STORAGECLASS pth_mutex_t NAME = gl_recursive_lock_initializer;
458 #  define gl_recursive_lock_initializer \
459      PTH_MUTEX_INIT
460 #  define glthread_recursive_lock_init(LOCK) \
461      (pth_in_use () && !pth_mutex_init (LOCK) ? errno : 0)
462 #  define glthread_recursive_lock_lock(LOCK) \
463      (pth_in_use () && !pth_mutex_acquire (LOCK, 0, NULL) ? errno : 0)
464 #  define glthread_recursive_lock_unlock(LOCK) \
465      (pth_in_use () && !pth_mutex_release (LOCK) ? errno : 0)
466 #  define glthread_recursive_lock_destroy(LOCK) \
467      ((void)(LOCK), 0)
468
469 /* -------------------------- gl_once_t datatype -------------------------- */
470
471 typedef pth_once_t gl_once_t;
472 # define gl_once_define(STORAGECLASS, NAME) \
473     STORAGECLASS pth_once_t NAME = PTH_ONCE_INIT;
474 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
475     (pth_in_use ()                                                             \
476      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
477      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
478 extern int glthread_once_multithreaded (pth_once_t *once_control, void (*initfunction) (void));
479 extern int glthread_once_singlethreaded (pth_once_t *once_control);
480
481 # ifdef __cplusplus
482 }
483 # endif
484
485 #endif
486
487 /* ========================================================================= */
488
489 #if USE_SOLARIS_THREADS
490
491 /* Use the old Solaris threads library.  */
492
493 # include <thread.h>
494 # include <synch.h>
495
496 # ifdef __cplusplus
497 extern "C" {
498 # endif
499
500 # if USE_SOLARIS_THREADS_WEAK
501
502 /* Use weak references to the old Solaris threads library.  */
503
504 #  pragma weak mutex_init
505 #  pragma weak mutex_lock
506 #  pragma weak mutex_unlock
507 #  pragma weak mutex_destroy
508 #  pragma weak rwlock_init
509 #  pragma weak rw_rdlock
510 #  pragma weak rw_wrlock
511 #  pragma weak rw_unlock
512 #  pragma weak rwlock_destroy
513 #  pragma weak thr_self
514
515 #  pragma weak thr_suspend
516 #  define thread_in_use() (thr_suspend != NULL)
517
518 # else
519
520 #  define thread_in_use() 1
521
522 # endif
523
524 /* -------------------------- gl_lock_t datatype -------------------------- */
525
526 typedef mutex_t gl_lock_t;
527 # define gl_lock_define(STORAGECLASS, NAME) \
528     STORAGECLASS mutex_t NAME;
529 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
530     STORAGECLASS mutex_t NAME = gl_lock_initializer;
531 # define gl_lock_initializer \
532     DEFAULTMUTEX
533 # define glthread_lock_init(LOCK) \
534     (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
535 # define glthread_lock_lock(LOCK) \
536     (thread_in_use () ? mutex_lock (LOCK) : 0)
537 # define glthread_lock_unlock(LOCK) \
538     (thread_in_use () ? mutex_unlock (LOCK) : 0)
539 # define glthread_lock_destroy(LOCK) \
540     (thread_in_use () ? mutex_destroy (LOCK) : 0)
541
542 /* ------------------------- gl_rwlock_t datatype ------------------------- */
543
544 typedef rwlock_t gl_rwlock_t;
545 # define gl_rwlock_define(STORAGECLASS, NAME) \
546     STORAGECLASS rwlock_t NAME;
547 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
548     STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
549 # define gl_rwlock_initializer \
550     DEFAULTRWLOCK
551 # define glthread_rwlock_init(LOCK) \
552     (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
553 # define glthread_rwlock_rdlock(LOCK) \
554     (thread_in_use () ? rw_rdlock (LOCK) : 0)
555 # define glthread_rwlock_wrlock(LOCK) \
556     (thread_in_use () ? rw_wrlock (LOCK) : 0)
557 # define glthread_rwlock_unlock(LOCK) \
558     (thread_in_use () ? rw_unlock (LOCK) : 0)
559 # define glthread_rwlock_destroy(LOCK) \
560     (thread_in_use () ? rwlock_destroy (LOCK) : 0)
561
562 /* --------------------- gl_recursive_lock_t datatype --------------------- */
563
564 /* Old Solaris threads did not have recursive locks.
565    We have to implement them ourselves.  */
566
567 typedef struct
568         {
569           mutex_t mutex;
570           thread_t owner;
571           unsigned long depth;
572         }
573         gl_recursive_lock_t;
574 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
575     STORAGECLASS gl_recursive_lock_t NAME;
576 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
577     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
578 # define gl_recursive_lock_initializer \
579     { DEFAULTMUTEX, (thread_t) 0, 0 }
580 # define glthread_recursive_lock_init(LOCK) \
581     (thread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
582 # define glthread_recursive_lock_lock(LOCK) \
583     (thread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
584 # define glthread_recursive_lock_unlock(LOCK) \
585     (thread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
586 # define glthread_recursive_lock_destroy(LOCK) \
587     (thread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
588 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
589 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
590 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
591 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
592
593 /* -------------------------- gl_once_t datatype -------------------------- */
594
595 typedef struct
596         {
597           volatile int inited;
598           mutex_t mutex;
599         }
600         gl_once_t;
601 # define gl_once_define(STORAGECLASS, NAME) \
602     STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
603 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
604     (thread_in_use ()                                                          \
605      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
606      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
607 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
608 extern int glthread_once_singlethreaded (gl_once_t *once_control);
609
610 # ifdef __cplusplus
611 }
612 # endif
613
614 #endif
615
616 /* ========================================================================= */
617
618 #if USE_WIN32_THREADS
619
620 # include <windows.h>
621
622 # ifdef __cplusplus
623 extern "C" {
624 # endif
625
626 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
627    Semaphore types, because
628      - we need only to synchronize inside a single process (address space),
629        not inter-process locking,
630      - we don't need to support trylock operations.  (TryEnterCriticalSection
631        does not work on Windows 95/98/ME.  Packages that need trylock usually
632        define their own mutex type.)  */
633
634 /* There is no way to statically initialize a CRITICAL_SECTION.  It needs
635    to be done lazily, once only.  For this we need spinlocks.  */
636
637 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
638
639 /* -------------------------- gl_lock_t datatype -------------------------- */
640
641 typedef struct
642         {
643           gl_spinlock_t guard; /* protects the initialization */
644           CRITICAL_SECTION lock;
645         }
646         gl_lock_t;
647 # define gl_lock_define(STORAGECLASS, NAME) \
648     STORAGECLASS gl_lock_t NAME;
649 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
650     STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
651 # define gl_lock_initializer \
652     { { 0, -1 } }
653 # define glthread_lock_init(LOCK) \
654     (glthread_lock_init_func (LOCK), 0)
655 # define glthread_lock_lock(LOCK) \
656     glthread_lock_lock_func (LOCK)
657 # define glthread_lock_unlock(LOCK) \
658     glthread_lock_unlock_func (LOCK)
659 # define glthread_lock_destroy(LOCK) \
660     glthread_lock_destroy_func (LOCK)
661 extern void glthread_lock_init_func (gl_lock_t *lock);
662 extern int glthread_lock_lock_func (gl_lock_t *lock);
663 extern int glthread_lock_unlock_func (gl_lock_t *lock);
664 extern int glthread_lock_destroy_func (gl_lock_t *lock);
665
666 /* ------------------------- gl_rwlock_t datatype ------------------------- */
667
668 /* It is impossible to implement read-write locks using plain locks, without
669    introducing an extra thread dedicated to managing read-write locks.
670    Therefore here we need to use the low-level Event type.  */
671
672 typedef struct
673         {
674           HANDLE *array; /* array of waiting threads, each represented by an event */
675           unsigned int count; /* number of waiting threads */
676           unsigned int alloc; /* length of allocated array */
677           unsigned int offset; /* index of first waiting thread in array */
678         }
679         gl_carray_waitqueue_t;
680 typedef struct
681         {
682           gl_spinlock_t guard; /* protects the initialization */
683           CRITICAL_SECTION lock; /* protects the remaining fields */
684           gl_carray_waitqueue_t waiting_readers; /* waiting readers */
685           gl_carray_waitqueue_t waiting_writers; /* waiting writers */
686           int runcount; /* number of readers running, or -1 when a writer runs */
687         }
688         gl_rwlock_t;
689 # define gl_rwlock_define(STORAGECLASS, NAME) \
690     STORAGECLASS gl_rwlock_t NAME;
691 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
692     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
693 # define gl_rwlock_initializer \
694     { { 0, -1 } }
695 # define glthread_rwlock_init(LOCK) \
696     (glthread_rwlock_init_func (LOCK), 0)
697 # define glthread_rwlock_rdlock(LOCK) \
698     glthread_rwlock_rdlock_func (LOCK)
699 # define glthread_rwlock_wrlock(LOCK) \
700     glthread_rwlock_wrlock_func (LOCK)
701 # define glthread_rwlock_unlock(LOCK) \
702     glthread_rwlock_unlock_func (LOCK)
703 # define glthread_rwlock_destroy(LOCK) \
704     glthread_rwlock_destroy_func (LOCK)
705 extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
706 extern int glthread_rwlock_rdlock_func (gl_rwlock_t *lock);
707 extern int glthread_rwlock_wrlock_func (gl_rwlock_t *lock);
708 extern int glthread_rwlock_unlock_func (gl_rwlock_t *lock);
709 extern int glthread_rwlock_destroy_func (gl_rwlock_t *lock);
710
711 /* --------------------- gl_recursive_lock_t datatype --------------------- */
712
713 /* The Win32 documentation says that CRITICAL_SECTION already implements a
714    recursive lock.  But we need not rely on it: It's easy to implement a
715    recursive lock without this assumption.  */
716
717 typedef struct
718         {
719           gl_spinlock_t guard; /* protects the initialization */
720           DWORD owner;
721           unsigned long depth;
722           CRITICAL_SECTION lock;
723         }
724         gl_recursive_lock_t;
725 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
726     STORAGECLASS gl_recursive_lock_t NAME;
727 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
728     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
729 # define gl_recursive_lock_initializer \
730     { { 0, -1 }, 0, 0 }
731 # define glthread_recursive_lock_init(LOCK) \
732     (glthread_recursive_lock_init_func (LOCK), 0)
733 # define glthread_recursive_lock_lock(LOCK) \
734     glthread_recursive_lock_lock_func (LOCK)
735 # define glthread_recursive_lock_unlock(LOCK) \
736     glthread_recursive_lock_unlock_func (LOCK)
737 # define glthread_recursive_lock_destroy(LOCK) \
738     glthread_recursive_lock_destroy_func (LOCK)
739 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
740 extern int glthread_recursive_lock_lock_func (gl_recursive_lock_t *lock);
741 extern int glthread_recursive_lock_unlock_func (gl_recursive_lock_t *lock);
742 extern int glthread_recursive_lock_destroy_func (gl_recursive_lock_t *lock);
743
744 /* -------------------------- gl_once_t datatype -------------------------- */
745
746 typedef struct
747         {
748           volatile int inited;
749           volatile long started;
750           CRITICAL_SECTION lock;
751         }
752         gl_once_t;
753 # define gl_once_define(STORAGECLASS, NAME) \
754     STORAGECLASS gl_once_t NAME = { -1, -1 };
755 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
756     (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
757 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
758
759 # ifdef __cplusplus
760 }
761 # endif
762
763 #endif
764
765 /* ========================================================================= */
766
767 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
768
769 /* Provide dummy implementation if threads are not supported.  */
770
771 /* -------------------------- gl_lock_t datatype -------------------------- */
772
773 typedef int gl_lock_t;
774 # define gl_lock_define(STORAGECLASS, NAME)
775 # define gl_lock_define_initialized(STORAGECLASS, NAME)
776 # define glthread_lock_init(NAME) 0
777 # define glthread_lock_lock(NAME) 0
778 # define glthread_lock_unlock(NAME) 0
779 # define glthread_lock_destroy(NAME) 0
780
781 /* ------------------------- gl_rwlock_t datatype ------------------------- */
782
783 typedef int gl_rwlock_t;
784 # define gl_rwlock_define(STORAGECLASS, NAME)
785 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
786 # define glthread_rwlock_init(NAME) 0
787 # define glthread_rwlock_rdlock(NAME) 0
788 # define glthread_rwlock_wrlock(NAME) 0
789 # define glthread_rwlock_unlock(NAME) 0
790 # define glthread_rwlock_destroy(NAME) 0
791
792 /* --------------------- gl_recursive_lock_t datatype --------------------- */
793
794 typedef int gl_recursive_lock_t;
795 # define gl_recursive_lock_define(STORAGECLASS, NAME)
796 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
797 # define glthread_recursive_lock_init(NAME) 0
798 # define glthread_recursive_lock_lock(NAME) 0
799 # define glthread_recursive_lock_unlock(NAME) 0
800 # define glthread_recursive_lock_destroy(NAME) 0
801
802 /* -------------------------- gl_once_t datatype -------------------------- */
803
804 typedef int gl_once_t;
805 # define gl_once_define(STORAGECLASS, NAME) \
806     STORAGECLASS gl_once_t NAME = 0;
807 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
808     (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
809
810 #endif
811
812 /* ========================================================================= */
813
814 /* Macros with built-in error handling.  */
815
816 /* -------------------------- gl_lock_t datatype -------------------------- */
817
818 #define gl_lock_init(NAME) \
819    do                                  \
820      {                                 \
821        if (glthread_lock_init (&NAME)) \
822          abort ();                     \
823      }                                 \
824    while (0)
825 #define gl_lock_lock(NAME) \
826    do                                  \
827      {                                 \
828        if (glthread_lock_lock (&NAME)) \
829          abort ();                     \
830      }                                 \
831    while (0)
832 #define gl_lock_unlock(NAME) \
833    do                                    \
834      {                                   \
835        if (glthread_lock_unlock (&NAME)) \
836          abort ();                       \
837      }                                   \
838    while (0)
839 #define gl_lock_destroy(NAME) \
840    do                                     \
841      {                                    \
842        if (glthread_lock_destroy (&NAME)) \
843          abort ();                        \
844      }                                    \
845    while (0)
846
847 /* ------------------------- gl_rwlock_t datatype ------------------------- */
848
849 #define gl_rwlock_init(NAME) \
850    do                                    \
851      {                                   \
852        if (glthread_rwlock_init (&NAME)) \
853          abort ();                       \
854      }                                   \
855    while (0)
856 #define gl_rwlock_rdlock(NAME) \
857    do                                      \
858      {                                     \
859        if (glthread_rwlock_rdlock (&NAME)) \
860          abort ();                         \
861      }                                     \
862    while (0)
863 #define gl_rwlock_wrlock(NAME) \
864    do                                      \
865      {                                     \
866        if (glthread_rwlock_wrlock (&NAME)) \
867          abort ();                         \
868      }                                     \
869    while (0)
870 #define gl_rwlock_unlock(NAME) \
871    do                                      \
872      {                                     \
873        if (glthread_rwlock_unlock (&NAME)) \
874          abort ();                         \
875      }                                     \
876    while (0)
877 #define gl_rwlock_destroy(NAME) \
878    do                                       \
879      {                                      \
880        if (glthread_rwlock_destroy (&NAME)) \
881          abort ();                          \
882      }                                      \
883    while (0)
884
885 /* --------------------- gl_recursive_lock_t datatype --------------------- */
886
887 #define gl_recursive_lock_init(NAME) \
888    do                                            \
889      {                                           \
890        if (glthread_recursive_lock_init (&NAME)) \
891          abort ();                               \
892      }                                           \
893    while (0)
894 #define gl_recursive_lock_lock(NAME) \
895    do                                            \
896      {                                           \
897        if (glthread_recursive_lock_lock (&NAME)) \
898          abort ();                               \
899      }                                           \
900    while (0)
901 #define gl_recursive_lock_unlock(NAME) \
902    do                                              \
903      {                                             \
904        if (glthread_recursive_lock_unlock (&NAME)) \
905          abort ();                                 \
906      }                                             \
907    while (0)
908 #define gl_recursive_lock_destroy(NAME) \
909    do                                               \
910      {                                              \
911        if (glthread_recursive_lock_destroy (&NAME)) \
912          abort ();                                  \
913      }                                              \
914    while (0)
915
916 /* -------------------------- gl_once_t datatype -------------------------- */
917
918 #define gl_once(NAME, INITFUNCTION) \
919    do                                           \
920      {                                          \
921        if (glthread_once (&NAME, INITFUNCTION)) \
922          abort ();                              \
923      }                                          \
924    while (0)
925
926 /* ========================================================================= */
927
928 #endif /* _LOCK_H */