maint: update all copyright year number ranges
[gnulib.git] / lib / glthread / cond.h
1 /* Condition variables for multithreading.
2    Copyright (C) 2005-2013 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, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Yoann Vandoorselaere <yoann@prelude-ids.org>, 2008.
18    Based on Bruno Haible <bruno@clisp.org> lock.h */
19
20 /*
21    Condition variables can be used for waiting until a condition
22    becomes true. In this respect, they are similar to wait queues. But
23    contrary to wait queues, condition variables have different
24    semantics that allows events to be lost when there is no thread
25    waiting for them.
26
27    Condition variable:
28      Type:                gl_cond_t
29      Declaration:         gl_cond_define(extern, name)
30      Initializer:         gl_cond_define_initialized(, name)
31      Initialization:      gl_cond_init (name);
32      Waiting:             gl_cond_wait (name, lock);
33      Timed wait:          bool timedout = gl_cond_timedwait (name, lock, abstime);
34                           where lock is a gl_lock_t variable (cf. <glthread/lock.h>)
35      Signaling:           gl_cond_signal (name);
36      Broadcasting:        gl_cond_broadcast (name);
37      De-initialization:   gl_cond_destroy (name);
38    Equivalent functions with control of error handling:
39      Initialization:      err = glthread_cond_init (&name);
40      Waiting:             err = glthread_cond_wait (&name);
41      Timed wait:          err = glthread_cond_timedwait (&name, &lock, abstime);
42      Signaling:           err = glthread_cond_signal (&name);
43      Broadcasting:        err = glthread_cond_broadcast (&name);
44      De-initialization:   err = glthread_cond_destroy (&name);
45 */
46
47
48 #ifndef _GLTHREAD_COND_H
49 #define _GLTHREAD_COND_H
50
51 #include <errno.h>
52 #include <stdbool.h>
53 #include <stdlib.h>
54 #include <time.h>
55
56 #include "glthread/lock.h"
57
58 _GL_INLINE_HEADER_BEGIN
59 #ifndef _GLTHREAD_COND_INLINE
60 # define _GLTHREAD_COND_INLINE _GL_INLINE
61 #endif
62
63 /* ========================================================================= */
64
65 #if USE_POSIX_THREADS
66
67 /* Use the POSIX threads library.  */
68
69 # include <pthread.h>
70
71 # ifdef __cplusplus
72 extern "C" {
73 # endif
74
75 # if PTHREAD_IN_USE_DETECTION_HARD
76
77 /* The pthread_in_use() detection needs to be done at runtime.  */
78 #  define pthread_in_use() \
79      glthread_in_use ()
80 extern int glthread_in_use (void);
81
82 # endif
83
84 # if USE_POSIX_THREADS_WEAK
85
86 /* Use weak references to the POSIX threads library.  */
87
88 /* Weak references avoid dragging in external libraries if the other parts
89    of the program don't use them.  Here we use them, because we don't want
90    every program that uses libintl to depend on libpthread.  This assumes
91    that libpthread would not be loaded after libintl; i.e. if libintl is
92    loaded first, by an executable that does not depend on libpthread, and
93    then a module is dynamically loaded that depends on libpthread, libintl
94    will not be multithread-safe.  */
95
96 /* The way to test at runtime whether libpthread is present is to test
97    whether a function pointer's value, such as &pthread_mutex_init, is
98    non-NULL.  However, some versions of GCC have a bug through which, in
99    PIC mode, &foo != NULL always evaluates to true if there is a direct
100    call to foo(...) in the same function.  To avoid this, we test the
101    address of a function in libpthread that we don't use.  */
102
103 #  pragma weak pthread_cond_init
104 #  pragma weak pthread_cond_wait
105 #  pragma weak pthread_cond_timedwait
106 #  pragma weak pthread_cond_signal
107 #  pragma weak pthread_cond_broadcast
108 #  pragma weak pthread_cond_destroy
109 #  ifndef pthread_self
110 #   pragma weak pthread_self
111 #  endif
112
113 #  if !PTHREAD_IN_USE_DETECTION_HARD
114 #   pragma weak pthread_cancel
115 #   define pthread_in_use() (pthread_cancel != NULL)
116 #  endif
117
118 # else
119
120 #  if !PTHREAD_IN_USE_DETECTION_HARD
121 #   define pthread_in_use() 1
122 #  endif
123
124 # endif
125
126 /* -------------------------- gl_cond_t datatype -------------------------- */
127
128 typedef pthread_cond_t gl_cond_t;
129 # define gl_cond_define(STORAGECLASS, NAME) \
130     STORAGECLASS gl_cond_t NAME;
131 # define gl_cond_define_initialized(STORAGECLASS, NAME) \
132     STORAGECLASS gl_cond_t NAME = gl_cond_initializer;
133 # define gl_cond_initializer \
134     PTHREAD_COND_INITIALIZER
135 # define glthread_cond_init(COND) \
136     (pthread_in_use () ? pthread_cond_init (COND, NULL) : 0)
137 # define glthread_cond_wait(COND, LOCK) \
138     (pthread_in_use () ? pthread_cond_wait (COND, LOCK) : 0)
139 # define glthread_cond_timedwait(COND, LOCK, ABSTIME) \
140     (pthread_in_use () ? pthread_cond_timedwait (COND, LOCK, ABSTIME) : 0)
141 # define glthread_cond_signal(COND) \
142     (pthread_in_use () ? pthread_cond_signal (COND) : 0)
143 # define glthread_cond_broadcast(COND) \
144     (pthread_in_use () ? pthread_cond_broadcast (COND) : 0)
145 # define glthread_cond_destroy(COND) \
146     (pthread_in_use () ? pthread_cond_destroy (COND) : 0)
147
148 # ifdef __cplusplus
149 }
150 # endif
151
152 #endif
153
154 /* ========================================================================= */
155
156 #if USE_PTH_THREADS
157
158 /* Use the GNU Pth threads library.  */
159
160 # include <pth.h>
161
162 # ifdef __cplusplus
163 extern "C" {
164 # endif
165
166 # if USE_PTH_THREADS_WEAK
167
168 /* Use weak references to the GNU Pth threads library.  */
169
170 #  pragma weak pth_cond_init
171 #  pragma weak pth_cond_await
172 #  pragma weak pth_cond_notify
173 #  pragma weak pth_event
174 #  pragma weak pth_timeout
175
176 #  pragma weak pth_cancel
177 #  define pth_in_use() (pth_cancel != NULL)
178
179 # else
180
181 #  define pth_in_use() 1
182
183 # endif
184
185 /* -------------------------- gl_cond_t datatype -------------------------- */
186
187 typedef pth_cond_t gl_cond_t;
188 # define gl_cond_define(STORAGECLASS, NAME) \
189     STORAGECLASS gl_cond_t NAME;
190 # define gl_cond_define_initialized(STORAGECLASS, NAME) \
191     STORAGECLASS gl_cond_t NAME = gl_cond_initializer;
192 # define gl_cond_initializer \
193     PTH_COND_INIT
194 # define glthread_cond_init(COND) \
195     (pth_in_use () && !pth_cond_init (COND) ? errno : 0)
196 # define glthread_cond_wait(COND, LOCK) \
197     (pth_in_use () && !pth_cond_await (COND, LOCK, NULL) ? errno : 0)
198 # define glthread_cond_timedwait(COND, LOCK, ABSTIME) \
199     (pth_in_use () ? glthread_cond_timedwait_multithreaded (COND, LOCK, ABSTIME) : 0)
200 # define glthread_cond_signal(COND) \
201     (pth_in_use () && !pth_cond_notify (COND, FALSE) ? errno : 0)
202 # define glthread_cond_broadcast(COND) \
203     (pth_in_use () && !pth_cond_notify (COND, TRUE) ? errno : 0)
204 # define glthread_cond_destroy(COND) 0
205 extern int glthread_cond_timedwait_multithreaded (gl_cond_t *cond, gl_lock_t *lock, struct timespec *abstime);
206
207 # ifdef __cplusplus
208 }
209 # endif
210
211 #endif
212
213 /* ========================================================================= */
214
215 #if USE_SOLARIS_THREADS
216
217 /* Use the old Solaris threads library.  */
218
219 # include <thread.h>
220 # include <synch.h>
221
222 # ifdef __cplusplus
223 extern "C" {
224 # endif
225
226 # if USE_SOLARIS_THREADS_WEAK
227
228 /* Use weak references to the old Solaris threads library.  */
229
230 #  pragma weak cond_init
231 #  pragma weak cond_wait
232 #  pragma weak cond_timedwait
233 #  pragma weak cond_signal
234 #  pragma weak cond_broadcast
235 #  pragma weak cond_destroy
236 #  pragma weak thr_suspend
237 #  define thread_in_use() (thr_suspend != NULL)
238
239 # else
240
241 #  define thread_in_use() 1
242
243 # endif
244
245 /* -------------------------- gl_cond_t datatype -------------------------- */
246
247 typedef cond_t gl_cond_t;
248 # define gl_cond_define(STORAGECLASS, NAME) \
249     STORAGECLASS gl_cond_t NAME;
250 # define gl_cond_define_initialized(STORAGECLASS, NAME) \
251     STORAGECLASS gl_cond_t NAME = gl_cond_initializer;
252 # define gl_cond_initializer \
253     DEFAULTCV
254 # define glthread_cond_init(COND) \
255     (pthread_in_use () ? cond_init (COND, USYNC_THREAD, NULL) : 0)
256 # define glthread_cond_wait(COND, LOCK) \
257     (pthread_in_use () ? cond_wait (COND, LOCK) : 0)
258 # define glthread_cond_timedwait(COND, LOCK, ABSTIME) \
259     (pthread_in_use () ? glthread_cond_timedwait_multithreaded (COND, LOCK, ABSTIME) : 0)
260 # define glthread_cond_signal(COND) \
261     (pthread_in_use () ? cond_signal (COND) : 0)
262 # define glthread_cond_broadcast(COND) \
263     (pthread_in_use () ? cond_broadcast (COND) : 0)
264 # define glthread_cond_destroy(COND) \
265     (pthread_in_use () ? cond_destroy (COND) : 0)
266 extern int glthread_cond_timedwait_multithreaded (gl_cond_t *cond, gl_lock_t *lock, struct timespec *abstime);
267
268 # ifdef __cplusplus
269 }
270 # endif
271
272 #endif
273
274 /* ========================================================================= */
275
276 #if USE_WINDOWS_THREADS
277
278 # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
279 # include <windows.h>
280
281 # ifdef __cplusplus
282 extern "C" {
283 # endif
284
285 /* -------------------------- gl_cond_t datatype -------------------------- */
286
287 struct gl_waitqueue_link
288 {
289   struct gl_waitqueue_link *wql_next;
290   struct gl_waitqueue_link *wql_prev;
291 };
292 typedef struct
293         {
294           struct gl_waitqueue_link wq_list; /* circular list of waiting threads */
295         }
296         gl_linked_waitqueue_t;
297 typedef struct
298         {
299           gl_spinlock_t guard; /* protects the initialization */
300           CRITICAL_SECTION lock; /* protects the remaining fields */
301           gl_linked_waitqueue_t waiters; /* waiting threads */
302         }
303         gl_cond_t;
304 # define gl_cond_define(STORAGECLASS, NAME) \
305     STORAGECLASS gl_cond_t NAME;
306 # define gl_cond_define_initialized(STORAGECLASS, NAME) \
307     STORAGECLASS gl_cond_t NAME = gl_cond_initializer;
308 # define gl_cond_initializer \
309     { { 0, -1 } }
310 # define glthread_cond_init(COND) \
311     glthread_cond_init_func (COND)
312 # define glthread_cond_wait(COND, LOCK) \
313     glthread_cond_wait_func (COND, LOCK)
314 # define glthread_cond_timedwait(COND, LOCK, ABSTIME) \
315     glthread_cond_timedwait_func (COND, LOCK, ABSTIME)
316 # define glthread_cond_signal(COND) \
317     glthread_cond_signal_func (COND)
318 # define glthread_cond_broadcast(COND) \
319     glthread_cond_broadcast_func (COND)
320 # define glthread_cond_destroy(COND) \
321     glthread_cond_destroy_func (COND)
322 extern int glthread_cond_init_func (gl_cond_t *cond);
323 extern int glthread_cond_wait_func (gl_cond_t *cond, gl_lock_t *lock);
324 extern int glthread_cond_timedwait_func (gl_cond_t *cond, gl_lock_t *lock, struct timespec *abstime);
325 extern int glthread_cond_signal_func (gl_cond_t *cond);
326 extern int glthread_cond_broadcast_func (gl_cond_t *cond);
327 extern int glthread_cond_destroy_func (gl_cond_t *cond);
328
329 # ifdef __cplusplus
330 }
331 # endif
332
333 #endif
334
335 /* ========================================================================= */
336
337 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
338
339 /* Provide dummy implementation if threads are not supported.  */
340
341 typedef int gl_cond_t;
342 # define gl_cond_define(STORAGECLASS, NAME)
343 # define gl_cond_define_initialized(STORAGECLASS, NAME)
344 # define glthread_cond_init(COND) 0
345 # define glthread_cond_wait(COND, LOCK) 0
346 # define glthread_cond_timedwait(COND, LOCK, ABSTIME) 0
347 # define glthread_cond_signal(COND) 0
348 # define glthread_cond_broadcast(COND) 0
349 # define glthread_cond_destroy(COND) 0
350
351 #endif
352
353 /* ========================================================================= */
354
355 /* Macros with built-in error handling.  */
356
357 #ifdef __cplusplus
358 extern "C" {
359 #endif
360
361 #define gl_cond_init(COND)             \
362    do                                  \
363      {                                 \
364        if (glthread_cond_init (&COND)) \
365          abort ();                     \
366      }                                 \
367    while (0)
368 #define gl_cond_wait(COND, LOCK)              \
369    do                                         \
370      {                                        \
371        if (glthread_cond_wait (&COND, &LOCK)) \
372          abort ();                            \
373      }                                        \
374    while (0)
375 #define gl_cond_timedwait(COND, LOCK, ABSTIME) \
376   gl_cond_timedwait_func (&COND, &LOCK, ABSTIME)
377 _GLTHREAD_COND_INLINE bool
378 gl_cond_timedwait_func (gl_cond_t *cond, gl_lock_t *lock, struct timespec *abstime)
379 {
380   int err = glthread_cond_timedwait (cond, lock, abstime);
381   if (err == ETIMEDOUT)
382     return true;
383   if (err != 0)
384     abort ();
385   return false;
386 }
387 #define gl_cond_signal(COND)             \
388    do                                    \
389      {                                   \
390        if (glthread_cond_signal (&COND)) \
391          abort ();                       \
392      }                                   \
393    while (0)
394 #define gl_cond_broadcast(COND)             \
395    do                                       \
396      {                                      \
397        if (glthread_cond_broadcast (&COND)) \
398          abort ();                          \
399      }                                      \
400    while (0)
401 #define gl_cond_destroy(COND)             \
402    do                                     \
403      {                                    \
404        if (glthread_cond_destroy (&COND)) \
405          abort ();                        \
406      }                                    \
407    while (0)
408
409 #ifdef __cplusplus
410 }
411 #endif
412
413 _GL_INLINE_HEADER_END
414
415 #endif /* _GLTHREAD_COND_H */