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