1 /* Locking in multithreaded situations.
2    Copyright (C) 2005-2009 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 /* -------------------------- gl_lock_t datatype -------------------------- */
98 
99 typedef pthread_mutex_t gl_lock_t;
100 # define gl_lock_define(STORAGECLASS, NAME) \
101     STORAGECLASS pthread_mutex_t NAME;
102 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
103     STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
104 # define gl_lock_initializer \
105     PTHREAD_MUTEX_INITIALIZER
106 # define glthread_lock_init(LOCK) \
107     (pthread_mutex_init (LOCK, NULL))
108 # define glthread_lock_lock(LOCK) \
109     (pthread_mutex_lock (LOCK))
110 # define glthread_lock_unlock(LOCK) \
111     (pthread_mutex_unlock (LOCK))
112 # define glthread_lock_destroy(LOCK) \
113     (pthread_mutex_destroy (LOCK))
114 
115 /* ------------------------- gl_rwlock_t datatype ------------------------- */
116 
117 # if HAVE_PTHREAD_RWLOCK
118 
119 #  ifdef PTHREAD_RWLOCK_INITIALIZER
120 
121 typedef pthread_rwlock_t gl_rwlock_t;
122 #   define gl_rwlock_define(STORAGECLASS, NAME) \
123       STORAGECLASS pthread_rwlock_t NAME;
124 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
125       STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
126 #   define gl_rwlock_initializer \
127       PTHREAD_RWLOCK_INITIALIZER
128 #   define glthread_rwlock_init(LOCK) \
129       (pthread_rwlock_init (LOCK, NULL))
130 #   define glthread_rwlock_rdlock(LOCK) \
131       (pthread_rwlock_rdlock (LOCK))
132 #   define glthread_rwlock_wrlock(LOCK) \
133       (pthread_rwlock_wrlock (LOCK))
134 #   define glthread_rwlock_unlock(LOCK) \
135       (pthread_rwlock_unlock (LOCK))
136 #   define glthread_rwlock_destroy(LOCK) \
137       (pthread_rwlock_destroy (LOCK))
138 
139 #  else
140 
141 typedef struct
142         {
143           int initialized;
144           pthread_mutex_t guard;   /* protects the initialization */
145           pthread_rwlock_t rwlock; /* read-write lock */
146         }
147         gl_rwlock_t;
148 #   define gl_rwlock_define(STORAGECLASS, NAME) \
149       STORAGECLASS gl_rwlock_t NAME;
150 #   define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
151       STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
152 #   define gl_rwlock_initializer \
153       { 0, PTHREAD_MUTEX_INITIALIZER }
154 extern int glthread_rwlock_init (gl_rwlock_t *lock);
155 extern int glthread_rwlock_rdlock (gl_rwlock_t *lock);
156 extern int glthread_rwlock_wrlock (gl_rwlock_t *lock);
157 extern int glthread_rwlock_unlock (gl_rwlock_t *lock);
158 extern int glthread_rwlock_destroy (gl_rwlock_t *lock);
159 
160 #  endif
161 
162 # else
163 
164 typedef struct
165         {
166           pthread_mutex_t lock; /* protects the remaining fields */
167           pthread_cond_t waiting_readers; /* waiting readers */
168           pthread_cond_t waiting_writers; /* waiting writers */
169           unsigned int waiting_writers_count; /* number of waiting writers */
170           int runcount; /* number of readers running, or -1 when a writer runs */
171         }
172         gl_rwlock_t;
173 # define gl_rwlock_define(STORAGECLASS, NAME) \
174     STORAGECLASS gl_rwlock_t NAME;
175 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
176     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
177 # define gl_rwlock_initializer \
178     { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
179 extern int glthread_rwlock_init (gl_rwlock_t *lock);
180 extern int glthread_rwlock_rdlock (gl_rwlock_t *lock);
181 extern int glthread_rwlock_wrlock (gl_rwlock_t *lock);
182 extern int glthread_rwlock_unlock (gl_rwlock_t *lock);
183 extern int glthread_rwlock_destroy (gl_rwlock_t *lock);
184 
185 # endif
186 
187 /* --------------------- gl_recursive_lock_t datatype --------------------- */
188 
189 # if HAVE_PTHREAD_MUTEX_RECURSIVE
190 
191 #  if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
192 
193 typedef pthread_mutex_t gl_recursive_lock_t;
194 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
195       STORAGECLASS pthread_mutex_t NAME;
196 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
197       STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
198 #   ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
199 #    define gl_recursive_lock_initializer \
200        PTHREAD_RECURSIVE_MUTEX_INITIALIZER
201 #   else
202 #    define gl_recursive_lock_initializer \
203        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
204 #   endif
205 #   define glthread_recursive_lock_lock(LOCK) \
206       (pthread_mutex_lock (LOCK))
207 #   define glthread_recursive_lock_unlock(LOCK) \
208       (pthread_mutex_unlock (LOCK))
209 #   define glthread_recursive_lock_destroy(LOCK) \
210       (pthread_mutex_destroy (LOCK))
211 extern int glthread_recursive_lock_init (gl_recursive_lock_t *lock);
212 
213 #  else
214 
215 typedef struct
216         {
217           pthread_mutex_t recmutex; /* recursive mutex */
218           pthread_mutex_t guard;    /* protects the initialization */
219           int initialized;
220         }
221         gl_recursive_lock_t;
222 #   define gl_recursive_lock_define(STORAGECLASS, NAME) \
223       STORAGECLASS gl_recursive_lock_t NAME;
224 #   define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
225       STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
226 #   define gl_recursive_lock_initializer \
227       { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
228 extern int glthread_recursive_lock_init (gl_recursive_lock_t *lock);
229 extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
230 extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
231 extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
232 
233 #  endif
234 
235 # else
236 
237 /* Old versions of POSIX threads on Solaris did not have recursive locks.
238    We have to implement them ourselves.  */
239 
240 typedef struct
241         {
242           pthread_mutex_t mutex;
243           pthread_t owner;
244           unsigned long depth;
245         }
246         gl_recursive_lock_t;
247 #  define gl_recursive_lock_define(STORAGECLASS, NAME) \
248      STORAGECLASS gl_recursive_lock_t NAME;
249 #  define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
250      STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
251 #  define gl_recursive_lock_initializer \
252      { PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
253 extern int glthread_recursive_lock_init (gl_recursive_lock_t *lock);
254 extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
255 extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
256 extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
257 
258 # endif
259 
260 /* -------------------------- gl_once_t datatype -------------------------- */
261 
262 typedef pthread_once_t gl_once_t;
263 # define gl_once_define(STORAGECLASS, NAME) \
264     STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
265 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
266     (pthread_once (ONCE_CONTROL, INITFUNCTION))
267 
268 # ifdef __cplusplus
269 }
270 # endif
271 
272 #endif
273 
274 /* ========================================================================= */
275 
276 #if USE_WIN32_THREADS
277 
278 # include <windows.h>
279 
280 # ifdef __cplusplus
281 extern "C" {
282 # endif
283 
284 /* We can use CRITICAL_SECTION directly, rather than the Win32 Event, Mutex,
285    Semaphore types, because
286      - we need only to synchronize inside a single process (address space),
287        not inter-process locking,
288      - we don't need to support trylock operations.  (TryEnterCriticalSection
289        does not work on Windows 95/98/ME.  Packages that need trylock usually
290        define their own mutex type.)  */
291 
292 /* There is no way to statically initialize a CRITICAL_SECTION.  It needs
293    to be done lazily, once only.  For this we need spinlocks.  */
294 
295 typedef struct { volatile int done; volatile long started; } gl_spinlock_t;
296 
297 /* -------------------------- gl_lock_t datatype -------------------------- */
298 
299 typedef struct
300         {
301           gl_spinlock_t guard; /* protects the initialization */
302           CRITICAL_SECTION lock;
303         }
304         gl_lock_t;
305 # define gl_lock_define(STORAGECLASS, NAME) \
306     STORAGECLASS gl_lock_t NAME;
307 # define gl_lock_define_initialized(STORAGECLASS, NAME) \
308     STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
309 # define gl_lock_initializer \
310     { { 0, -1 } }
311 # define glthread_lock_init(LOCK) \
312     (glthread_lock_init_func (LOCK), 0)
313 extern void glthread_lock_init_func (gl_lock_t *lock);
314 extern int glthread_lock_lock (gl_lock_t *lock);
315 extern int glthread_lock_unlock (gl_lock_t *lock);
316 extern int glthread_lock_destroy (gl_lock_t *lock);
317 
318 /* ------------------------- gl_rwlock_t datatype ------------------------- */
319 
320 /* It is impossible to implement read-write locks using plain locks, without
321    introducing an extra thread dedicated to managing read-write locks.
322    Therefore here we need to use the low-level Event type.  */
323 
324 typedef struct
325         {
326           HANDLE *array; /* array of waiting threads, each represented by an event */
327           unsigned int count; /* number of waiting threads */
328           unsigned int alloc; /* length of allocated array */
329           unsigned int offset; /* index of first waiting thread in array */
330         }
331         gl_waitqueue_t;
332 typedef struct
333         {
334           gl_spinlock_t guard; /* protects the initialization */
335           CRITICAL_SECTION lock; /* protects the remaining fields */
336           gl_waitqueue_t waiting_readers; /* waiting readers */
337           gl_waitqueue_t waiting_writers; /* waiting writers */
338           int runcount; /* number of readers running, or -1 when a writer runs */
339         }
340         gl_rwlock_t;
341 # define gl_rwlock_define(STORAGECLASS, NAME) \
342     STORAGECLASS gl_rwlock_t NAME;
343 # define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
344     STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
345 # define gl_rwlock_initializer \
346     { { 0, -1 } }
347 # define glthread_rwlock_init(LOCK) \
348     (glthread_rwlock_init_func (LOCK), 0)
349 extern void glthread_rwlock_init_func (gl_rwlock_t *lock);
350 extern int glthread_rwlock_rdlock (gl_rwlock_t *lock);
351 extern int glthread_rwlock_wrlock (gl_rwlock_t *lock);
352 extern int glthread_rwlock_unlock (gl_rwlock_t *lock);
353 extern int glthread_rwlock_destroy (gl_rwlock_t *lock);
354 
355 /* --------------------- gl_recursive_lock_t datatype --------------------- */
356 
357 /* The Win32 documentation says that CRITICAL_SECTION already implements a
358    recursive lock.  But we need not rely on it: It's easy to implement a
359    recursive lock without this assumption.  */
360 
361 typedef struct
362         {
363           gl_spinlock_t guard; /* protects the initialization */
364           DWORD owner;
365           unsigned long depth;
366           CRITICAL_SECTION lock;
367         }
368         gl_recursive_lock_t;
369 # define gl_recursive_lock_define(STORAGECLASS, NAME) \
370     STORAGECLASS gl_recursive_lock_t NAME;
371 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
372     STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
373 # define gl_recursive_lock_initializer \
374     { { 0, -1 }, 0, 0 }
375 # define glthread_recursive_lock_init(LOCK) \
376     (glthread_recursive_lock_init_func (LOCK), 0)
377 extern void glthread_recursive_lock_init_func (gl_recursive_lock_t *lock);
378 extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
379 extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
380 extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
381 
382 /* -------------------------- gl_once_t datatype -------------------------- */
383 
384 typedef struct
385         {
386           volatile int inited;
387           volatile long started;
388           CRITICAL_SECTION lock;
389         }
390         gl_once_t;
391 # define gl_once_define(STORAGECLASS, NAME) \
392     STORAGECLASS gl_once_t NAME = { -1, -1 };
393 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
394     (glthread_once_func (ONCE_CONTROL, INITFUNCTION), 0)
395 extern void glthread_once_func (gl_once_t *once_control, void (*initfunction) (void));
396 
397 # ifdef __cplusplus
398 }
399 # endif
400 
401 #endif
402 
403 /* ========================================================================= */
404 
405 #if !(USE_POSIX_THREADS || USE_WIN32_THREADS)
406 
407 /* Provide dummy implementation if threads are not supported.  */
408 
409 /* -------------------------- gl_lock_t datatype -------------------------- */
410 
411 typedef int gl_lock_t;
412 # define gl_lock_define(STORAGECLASS, NAME)
413 # define gl_lock_define_initialized(STORAGECLASS, NAME)
414 # define glthread_lock_init(NAME) 0
415 # define glthread_lock_lock(NAME) 0
416 # define glthread_lock_unlock(NAME) 0
417 # define glthread_lock_destroy(NAME) 0
418 
419 /* ------------------------- gl_rwlock_t datatype ------------------------- */
420 
421 typedef int gl_rwlock_t;
422 # define gl_rwlock_define(STORAGECLASS, NAME)
423 # define gl_rwlock_define_initialized(STORAGECLASS, NAME)
424 # define glthread_rwlock_init(NAME) 0
425 # define glthread_rwlock_rdlock(NAME) 0
426 # define glthread_rwlock_wrlock(NAME) 0
427 # define glthread_rwlock_unlock(NAME) 0
428 # define glthread_rwlock_destroy(NAME) 0
429 
430 /* --------------------- gl_recursive_lock_t datatype --------------------- */
431 
432 typedef int gl_recursive_lock_t;
433 # define gl_recursive_lock_define(STORAGECLASS, NAME)
434 # define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
435 # define glthread_recursive_lock_init(NAME) 0
436 # define glthread_recursive_lock_lock(NAME) 0
437 # define glthread_recursive_lock_unlock(NAME) 0
438 # define glthread_recursive_lock_destroy(NAME) 0
439 
440 /* -------------------------- gl_once_t datatype -------------------------- */
441 
442 typedef int gl_once_t;
443 # define gl_once_define(STORAGECLASS, NAME) \
444     STORAGECLASS gl_once_t NAME = 0;
445 # define glthread_once(ONCE_CONTROL, INITFUNCTION) \
446     (*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
447 
448 #endif
449 
450 /* ========================================================================= */
451 
452 /* Macros with built-in error handling.  */
453 
454 /* -------------------------- gl_lock_t datatype -------------------------- */
455 
456 #define gl_lock_init(NAME) \
457    do                                  \
458      {                                 \
459        if (glthread_lock_init (&NAME)) \
460          abort ();                     \
461      }                                 \
462    while (0)
463 #define gl_lock_lock(NAME) \
464    do                                  \
465      {                                 \
466        if (glthread_lock_lock (&NAME)) \
467          abort ();                     \
468      }                                 \
469    while (0)
470 #define gl_lock_unlock(NAME) \
471    do                                    \
472      {                                   \
473        if (glthread_lock_unlock (&NAME)) \
474          abort ();                       \
475      }                                   \
476    while (0)
477 #define gl_lock_destroy(NAME) \
478    do                                     \
479      {                                    \
480        if (glthread_lock_destroy (&NAME)) \
481          abort ();                        \
482      }                                    \
483    while (0)
484 
485 /* ------------------------- gl_rwlock_t datatype ------------------------- */
486 
487 #define gl_rwlock_init(NAME) \
488    do                                    \
489      {                                   \
490        if (glthread_rwlock_init (&NAME)) \
491          abort ();                       \
492      }                                   \
493    while (0)
494 #define gl_rwlock_rdlock(NAME) \
495    do                                      \
496      {                                     \
497        if (glthread_rwlock_rdlock (&NAME)) \
498          abort ();                         \
499      }                                     \
500    while (0)
501 #define gl_rwlock_wrlock(NAME) \
502    do                                      \
503      {                                     \
504        if (glthread_rwlock_wrlock (&NAME)) \
505          abort ();                         \
506      }                                     \
507    while (0)
508 #define gl_rwlock_unlock(NAME) \
509    do                                      \
510      {                                     \
511        if (glthread_rwlock_unlock (&NAME)) \
512          abort ();                         \
513      }                                     \
514    while (0)
515 #define gl_rwlock_destroy(NAME) \
516    do                                       \
517      {                                      \
518        if (glthread_rwlock_destroy (&NAME)) \
519          abort ();                          \
520      }                                      \
521    while (0)
522 
523 /* --------------------- gl_recursive_lock_t datatype --------------------- */
524 
525 #define gl_recursive_lock_init(NAME) \
526    do                                            \
527      {                                           \
528        if (glthread_recursive_lock_init (&NAME)) \
529          abort ();                               \
530      }                                           \
531    while (0)
532 #define gl_recursive_lock_lock(NAME) \
533    do                                            \
534      {                                           \
535        if (glthread_recursive_lock_lock (&NAME)) \
536          abort ();                               \
537      }                                           \
538    while (0)
539 #define gl_recursive_lock_unlock(NAME) \
540    do                                              \
541      {                                             \
542        if (glthread_recursive_lock_unlock (&NAME)) \
543          abort ();                                 \
544      }                                             \
545    while (0)
546 #define gl_recursive_lock_destroy(NAME) \
547    do                                               \
548      {                                              \
549        if (glthread_recursive_lock_destroy (&NAME)) \
550          abort ();                                  \
551      }                                              \
552    while (0)
553 
554 /* -------------------------- gl_once_t datatype -------------------------- */
555 
556 #define gl_once(NAME, INITFUNCTION) \
557    do                                           \
558      {                                          \
559        if (glthread_once (&NAME, INITFUNCTION)) \
560          abort ();                              \
561      }                                          \
562    while (0)
563 
564 /* ========================================================================= */
565 
566 #endif /* _LOCK_H */
567