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