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