Move the lock and tls source files into a subdirectory.
[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
84 /* ========================================================================= */
85
86 #if USE_POSIX_THREADS
87
88 /* Use the POSIX threads library.  */
89
90 # include <pthread.h>
91 # include <stdlib.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 # include <stdlib.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 # include <stdlib.h>
496
497 # ifdef __cplusplus
498 extern "C" {
499 # endif
500
501 # if USE_SOLARIS_THREADS_WEAK
502
503 /* Use weak references to the old Solaris threads library.  */
504
505 #  pragma weak mutex_init
506 #  pragma weak mutex_lock
507 #  pragma weak mutex_unlock
508 #  pragma weak mutex_destroy
509 #  pragma weak rwlock_init
510 #  pragma weak rw_rdlock
511 #  pragma weak rw_wrlock
512 #  pragma weak rw_unlock
513 #  pragma weak rwlock_destroy
514 #  pragma weak thr_self
515
516 #  pragma weak thr_suspend
517 #  define thread_in_use() (thr_suspend != NULL)
518
519 # else
520
521 #  define thread_in_use() 1
522
523 # endif
524
525 /* -------------------------- gl_lock_t datatype -------------------------- */
526
527 typedef mutex_t gl_lock_t;
528 # define gl_lock_define(STORAGECLASS, NAME) \
529     STORAGECLASS mutex_t NAME;
530 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
531     STORAGECLASS mutex_t NAME = gl_lock_initializer;
532 # define gl_lock_initializer \
533     DEFAULTMUTEX
534 # define glthread_lock_init(LOCK) \
535     (thread_in_use () ? mutex_init (LOCK, USYNC_THREAD, NULL) : 0)
536 # define glthread_lock_lock(LOCK) \
537     (thread_in_use () ? mutex_lock (LOCK) : 0)
538 # define glthread_lock_unlock(LOCK) \
539     (thread_in_use () ? mutex_unlock (LOCK) : 0)
540 # define glthread_lock_destroy(LOCK) \
541     (thread_in_use () ? mutex_destroy (LOCK) : 0)
542
543 /* ------------------------- gl_rwlock_t datatype ------------------------- */
544
545 typedef rwlock_t gl_rwlock_t;
546 # define gl_rwlock_define(STORAGECLASS, NAME) \
547     STORAGECLASS rwlock_t NAME;
548 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
549     STORAGECLASS rwlock_t NAME = gl_rwlock_initializer;
550 # define gl_rwlock_initializer \
551     DEFAULTRWLOCK
552 # define glthread_rwlock_init(LOCK) \
553     (thread_in_use () ? rwlock_init (LOCK, USYNC_THREAD, NULL) : 0)
554 # define glthread_rwlock_rdlock(LOCK) \
555     (thread_in_use () ? rw_rdlock (LOCK) : 0)
556 # define glthread_rwlock_wrlock(LOCK) \
557     (thread_in_use () ? rw_wrlock (LOCK) : 0)
558 # define glthread_rwlock_unlock(LOCK) \
559     (thread_in_use () ? rw_unlock (LOCK) : 0)
560 # define glthread_rwlock_destroy(LOCK) \
561     (thread_in_use () ? rwlock_destroy (LOCK) : 0)
562
563 /* --------------------- gl_recursive_lock_t datatype --------------------- */
564
565 /* Old Solaris threads did not have recursive locks.
566    We have to implement them ourselves.  */
567
568 typedef struct
569         {
570           mutex_t mutex;
571           thread_t owner;
572           unsigned long depth;
573         }
574         gl_recursive_lock_t;
575 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
576     STORAGECLASS gl_recursive_lock_t NAME;
577 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
578     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
579 # define gl_recursive_lock_initializer \
580     { DEFAULTMUTEX, (thread_t) 0, 0 }
581 # define glthread_recursive_lock_init(LOCK) \
582     do                                          \
583       {                                         \
584         if (thread_in_use ())                   \
585           glthread_recursive_lock_init_multithreaded (LOCK); \
586       }                                         \
587     while (0)
588 # define glthread_recursive_lock_lock(LOCK) \
589     do                                          \
590       {                                         \
591         if (thread_in_use ())                   \
592           glthread_recursive_lock_lock_multithreaded (LOCK); \
593       }                                         \
594     while (0)
595 # define glthread_recursive_lock_unlock(LOCK) \
596     do                                            \
597       {                                           \
598         if (thread_in_use ())                     \
599           glthread_recursive_lock_unlock_multithreaded (LOCK); \
600       }                                           \
601     while (0)
602 # define glthread_recursive_lock_destroy(LOCK) \
603     do                                             \
604       {                                            \
605         if (thread_in_use ())                      \
606           glthread_recursive_lock_destroy_multithreaded (LOCK); \
607       }                                            \
608     while (0)
609 extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
610 extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
611 extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
612 extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
613
614 /* -------------------------- gl_once_t datatype -------------------------- */
615
616 typedef struct
617         {
618           volatile int inited;
619           mutex_t mutex;
620         }
621         gl_once_t;
622 # define gl_once_define(STORAGECLASS, NAME) \
623     STORAGECLASS gl_once_t NAME = { 0, DEFAULTMUTEX };
624 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
625     (thread_in_use ()                                                          \
626      ? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION)                \
627      : (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
628 extern int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void));
629 extern int glthread_once_singlethreaded (gl_once_t *once_control);
630
631 # ifdef __cplusplus
632 }
633 # endif
634
635 #endif
636
637 /* ========================================================================= */
638
639 #if USE_WIN32_THREADS
640
641 # include <windows.h>
642
643 # ifdef __cplusplus
644 extern "C" {
645 # endif
646
647 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
648    Semaphore types, because
649      - we need only to synchronize inside a single process (address space),
650        not inter-process locking,
651      - we don't need to support trylock operations.  (TryEnterCriticalSection
652        does not work on Windows 95/98/ME.  Packages that need trylock usually
653        define their own mutex type.)  */
654
655 /* There is no way to statically initialize a CRITICAL_SECTION.  It needs
656    to be done lazily, once only.  For this we need spinlocks.  */
657
658 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
659
660 /* -------------------------- gl_lock_t datatype -------------------------- */
661
662 typedef struct
663         {
664           gl_spinlock_t guard; /* protects the initialization */
665           CRITICAL_SECTION lock;
666         }
667         gl_lock_t;
668 # define gl_lock_define(STORAGECLASS, NAME) \
669     STORAGECLASS gl_lock_t NAME;
670 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
671     STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
672 # define gl_lock_initializer \
673     { { 0, -1 } }
674 # define glthread_lock_init(LOCK) \
675     (glthread_lock_init_func (LOCK), 0)
676 extern void glthread_lock_init_func (gl_lock_t *lock);
677 extern int glthread_lock_lock (gl_lock_t *lock);
678 extern int glthread_lock_unlock (gl_lock_t *lock);
679 extern int glthread_lock_destroy (gl_lock_t *lock);
680
681 /* ------------------------- gl_rwlock_t datatype ------------------------- */
682
683 /* It is impossible to implement read-write locks using plain locks, without
684    introducing an extra thread dedicated to managing read-write locks.
685    Therefore here we need to use the low-level Event type.  */
686
687 typedef struct
688         {
689           HANDLE *array; /* array of waiting threads, each represented by an event */
690           unsigned int count; /* number of waiting threads */
691           unsigned int alloc; /* length of allocated array */
692           unsigned int offset; /* index of first waiting thread in array */
693         }
694         gl_waitqueue_t;
695 typedef struct
696         {
697           gl_spinlock_t guard; /* protects the initialization */
698           CRITICAL_SECTION lock; /* protects the remaining fields */
699           gl_waitqueue_t waiting_readers; /* waiting readers */
700           gl_waitqueue_t waiting_writers; /* waiting writers */
701           int runcount; /* number of readers running, or -1 when a writer runs */
702         }
703         gl_rwlock_t;
704 # define gl_rwlock_define(STORAGECLASS, NAME) \
705     STORAGECLASS gl_rwlock_t NAME;
706 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
707     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
708 # define gl_rwlock_initializer \
709     { { 0, -1 } }
710 # define glthread_rwlock_init(LOCK) \
711     (glthread_rwlock_init_func (LOCK), 0)
712 extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
713 extern int glthread_rwlock_rdlock (gl_rwlock_t *lock);
714 extern int glthread_rwlock_wrlock (gl_rwlock_t *lock);
715 extern int glthread_rwlock_unlock (gl_rwlock_t *lock);
716 extern int glthread_rwlock_destroy (gl_rwlock_t *lock);
717
718 /* --------------------- gl_recursive_lock_t datatype --------------------- */
719
720 /* The Win32 documentation says that CRITICAL_SECTION already implements a
721    recursive lock.  But we need not rely on it: It's easy to implement a
722    recursive lock without this assumption.  */
723
724 typedef struct
725         {
726           gl_spinlock_t guard; /* protects the initialization */
727           DWORD owner;
728           unsigned long depth;
729           CRITICAL_SECTION lock;
730         }
731         gl_recursive_lock_t;
732 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
733     STORAGECLASS gl_recursive_lock_t NAME;
734 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
735     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
736 # define gl_recursive_lock_initializer \
737     { { 0, -1 }, 0, 0 }
738 # define glthread_recursive_lock_init(LOCK) \
739     (glthread_recursive_lock_init_func (LOCK), 0)
740 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
741 extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
742 extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
743 extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
744
745 /* -------------------------- gl_once_t datatype -------------------------- */
746
747 typedef struct
748         {
749           volatile int inited;
750           volatile long started;
751           CRITICAL_SECTION lock;
752         }
753         gl_once_t;
754 # define gl_once_define(STORAGECLASS, NAME) \
755     STORAGECLASS gl_once_t NAME = { -1, -1 };
756 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
757     (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
758 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
759
760 # ifdef __cplusplus
761 }
762 # endif
763
764 #endif
765
766 /* ========================================================================= */
767
768 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
769
770 /* Provide dummy implementation if threads are not supported.  */
771
772 /* -------------------------- gl_lock_t datatype -------------------------- */
773
774 typedef int gl_lock_t;
775 # define gl_lock_define(STORAGECLASS, NAME)
776 # define gl_lock_define_initialized(STORAGECLASS, NAME)
777 # define glthread_lock_init(NAME) 0
778 # define glthread_lock_lock(NAME) 0
779 # define glthread_lock_unlock(NAME) 0
780 # define glthread_lock_destroy(NAME) 0
781
782 /* ------------------------- gl_rwlock_t datatype ------------------------- */
783
784 typedef int gl_rwlock_t;
785 # define gl_rwlock_define(STORAGECLASS, NAME)
786 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
787 # define glthread_rwlock_init(NAME) 0
788 # define glthread_rwlock_rdlock(NAME) 0
789 # define glthread_rwlock_wrlock(NAME) 0
790 # define glthread_rwlock_unlock(NAME) 0
791 # define glthread_rwlock_destroy(NAME) 0
792
793 /* --------------------- gl_recursive_lock_t datatype --------------------- */
794
795 typedef int gl_recursive_lock_t;
796 # define gl_recursive_lock_define(STORAGECLASS, NAME)
797 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
798 # define glthread_recursive_lock_init(NAME) 0
799 # define glthread_recursive_lock_lock(NAME) 0
800 # define glthread_recursive_lock_unlock(NAME) 0
801 # define glthread_recursive_lock_destroy(NAME) 0
802
803 /* -------------------------- gl_once_t datatype -------------------------- */
804
805 typedef int gl_once_t;
806 # define gl_once_define(STORAGECLASS, NAME) \
807     STORAGECLASS gl_once_t NAME = 0;
808 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
809     (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
810
811 #endif
812
813 /* ========================================================================= */
814
815 /* Macros with built-in error handling.  */
816
817 /* -------------------------- gl_lock_t datatype -------------------------- */
818
819 #define gl_lock_init(NAME) \
820    do                                  \
821      {                                 \
822        if (glthread_lock_init (&NAME)) \
823          abort ();                     \
824      }                                 \
825    while (0)
826 #define gl_lock_lock(NAME) \
827    do                                  \
828      {                                 \
829        if (glthread_lock_lock (&NAME)) \
830          abort ();                     \
831      }                                 \
832    while (0)
833 #define gl_lock_unlock(NAME) \
834    do                                    \
835      {                                   \
836        if (glthread_lock_unlock (&NAME)) \
837          abort ();                       \
838      }                                   \
839    while (0)
840 #define gl_lock_destroy(NAME) \
841    do                                     \
842      {                                    \
843        if (glthread_lock_destroy (&NAME)) \
844          abort ();                        \
845      }                                    \
846    while (0)
847
848 /* ------------------------- gl_rwlock_t datatype ------------------------- */
849
850 #define gl_rwlock_init(NAME) \
851    do                                    \
852      {                                   \
853        if (glthread_rwlock_init (&NAME)) \
854          abort ();                       \
855      }                                   \
856    while (0)
857 #define gl_rwlock_rdlock(NAME) \
858    do                                      \
859      {                                     \
860        if (glthread_rwlock_rdlock (&NAME)) \
861          abort ();                         \
862      }                                     \
863    while (0)
864 #define gl_rwlock_wrlock(NAME) \
865    do                                      \
866      {                                     \
867        if (glthread_rwlock_wrlock (&NAME)) \
868          abort ();                         \
869      }                                     \
870    while (0)
871 #define gl_rwlock_unlock(NAME) \
872    do                                      \
873      {                                     \
874        if (glthread_rwlock_unlock (&NAME)) \
875          abort ();                         \
876      }                                     \
877    while (0)
878 #define gl_rwlock_destroy(NAME) \
879    do                                       \
880      {                                      \
881        if (glthread_rwlock_destroy (&NAME)) \
882          abort ();                          \
883      }                                      \
884    while (0)
885
886 /* --------------------- gl_recursive_lock_t datatype --------------------- */
887
888 #define gl_recursive_lock_init(NAME) \
889    do                                            \
890      {                                           \
891        if (glthread_recursive_lock_init (&NAME)) \
892          abort ();                               \
893      }                                           \
894    while (0)
895 #define gl_recursive_lock_lock(NAME) \
896    do                                            \
897      {                                           \
898        if (glthread_recursive_lock_lock (&NAME)) \
899          abort ();                               \
900      }                                           \
901    while (0)
902 #define gl_recursive_lock_unlock(NAME) \
903    do                                              \
904      {                                             \
905        if (glthread_recursive_lock_unlock (&NAME)) \
906          abort ();                                 \
907      }                                             \
908    while (0)
909 #define gl_recursive_lock_destroy(NAME) \
910    do                                               \
911      {                                              \
912        if (glthread_recursive_lock_destroy (&NAME)) \
913          abort ();                                  \
914      }                                              \
915    while (0)
916
917 /* -------------------------- gl_once_t datatype -------------------------- */
918
919 #define gl_once(NAME, INITFUNCTION) \
920    do                                           \
921      {                                          \
922        if (glthread_once (&NAME, INITFUNCTION)) \
923          abort ();                              \
924      }                                          \
925    while (0)
926
927 /* ========================================================================= */
928
929 #endif /* _LOCK_H */