1 /* Condition variables for multithreading.
2 Copyright (C) 2005-2008 Free Software Foundation, Inc.
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)
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.
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. */
18 /* Written by Yoann Vandoorselaere <yoann@prelude-ids.org>, 2008.
19 Based on Bruno Haible <bruno@clisp.org> lock.h */
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
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);
49 #ifndef _GLTHREAD_COND_H
50 #define _GLTHREAD_COND_H
57 #include "glthread/lock.h"
59 /* ========================================================================= */
63 /* Use the POSIX threads library. */
71 # if PTHREAD_IN_USE_DETECTION_HARD
73 /* The pthread_in_use() detection needs to be done at runtime. */
74 # define pthread_in_use() \
76 extern int glthread_in_use (void);
80 # if USE_POSIX_THREADS_WEAK
82 /* Use weak references to the POSIX threads library. */
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. */
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. */
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
109 # if !PTHREAD_IN_USE_DETECTION_HARD
110 # pragma weak pthread_cancel
111 # define pthread_in_use() (pthread_cancel != NULL)
116 # if !PTHREAD_IN_USE_DETECTION_HARD
117 # define pthread_in_use() 1
122 /* -------------------------- gl_cond_t datatype -------------------------- */
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)
150 /* ========================================================================= */
154 /* Use the GNU Pth threads library. */
162 # if USE_PTH_THREADS_WEAK
164 /* Use weak references to the GNU Pth threads library. */
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
172 # pragma weak pth_cancel
173 # define pth_in_use() (pth_cancel != NULL)
177 # define pth_in_use() 1
181 /* -------------------------- gl_cond_t datatype -------------------------- */
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 \
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);
209 /* ========================================================================= */
211 #if USE_SOLARIS_THREADS
213 /* Use the old Solaris threads library. */
222 # if USE_SOLARIS_THREADS_WEAK
224 /* Use weak references to the old Solaris threads library. */
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)
237 # define thread_in_use() 1
241 /* -------------------------- gl_cond_t datatype -------------------------- */
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 \
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);
270 /* ========================================================================= */
272 #if USE_WIN32_THREADS
274 # include <windows.h>
280 /* -------------------------- gl_cond_t datatype -------------------------- */
284 gl_spinlock_t guard; /* protects the initialization */
285 CRITICAL_SECTION lock; /* protects the remaining fields */
286 HANDLE event; /* an event configured for manual reset */
287 unsigned int waiters_count; /* number of threads currently waiting */
288 unsigned int release_count; /* number of threads that are currently
289 being notified but have not yet
291 release_count <= waiters_count */
292 unsigned int wait_generation_count; /* incremented each time a signal
293 or broadcast is performed */
296 # define gl_cond_define(STORAGECLASS, NAME) \
297 STORAGECLASS gl_cond_t NAME;
298 # define gl_cond_define_initialized(STORAGECLASS, NAME) \
299 STORAGECLASS gl_cond_t NAME = gl_cond_initializer;
300 # define gl_cond_initializer \
302 # define glthread_cond_init(COND) \
303 glthread_cond_init_func (COND)
304 # define glthread_cond_wait(COND, LOCK) \
305 glthread_cond_wait_func (COND, LOCK)
306 # define glthread_cond_timedwait(COND, LOCK, ABSTIME) \
307 glthread_cond_timedwait_func (COND, LOCK, ABSTIME)
308 # define glthread_cond_signal(COND) \
309 glthread_cond_signal_func (COND)
310 # define glthread_cond_broadcast(COND) \
311 glthread_cond_broadcast_func (COND)
312 # define glthread_cond_destroy(COND) \
313 glthread_cond_destroy_func (COND)
314 extern int glthread_cond_init_func (gl_cond_t *cond);
315 extern int glthread_cond_wait_func (gl_cond_t *cond, gl_lock_t *lock);
316 extern int glthread_cond_timedwait_func (gl_cond_t *cond, gl_lock_t *lock, struct timespec *abstime);
317 extern int glthread_cond_signal_func (gl_cond_t *cond);
318 extern int glthread_cond_broadcast_func (gl_cond_t *cond);
319 extern int glthread_cond_destroy_func (gl_cond_t *cond);
327 /* ========================================================================= */
329 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
331 /* Provide dummy implementation if threads are not supported. */
333 typedef int gl_cond_t;
334 # define gl_cond_define(STORAGECLASS, NAME)
335 # define gl_cond_define_initialized(STORAGECLASS, NAME)
336 # define glthread_cond_init(COND) 0
337 # define glthread_cond_wait(COND, LOCK) 0
338 # define glthread_cond_timedwait(COND, LOCK, ABSTIME) 0
339 # define glthread_cond_signal(COND) 0
340 # define glthread_cond_broadcast(COND) 0
341 # define glthread_cond_destroy(COND) 0
345 /* ========================================================================= */
347 /* Macros with built-in error handling. */
353 #define gl_cond_init(COND) \
356 if (glthread_cond_init (&COND)) \
360 #define gl_cond_wait(COND, LOCK) \
363 if (glthread_cond_wait (&COND, &LOCK)) \
367 #define gl_cond_timedwait(COND, LOCK, ABSTIME) \
368 gl_cond_timedwait_func (&COND, &LOCK, ABSTIME)
370 gl_cond_timedwait_func (gl_cond_t *cond, gl_lock_t *lock, struct timespec *abstime)
372 int err = glthread_cond_timedwait (cond, lock, abstime);
373 if (err == ETIMEDOUT)
379 #define gl_cond_signal(COND) \
382 if (glthread_cond_signal (&COND)) \
386 #define gl_cond_broadcast(COND) \
389 if (glthread_cond_broadcast (&COND)) \
393 #define gl_cond_destroy(COND) \
396 if (glthread_cond_destroy (&COND)) \
405 #endif /* _GLTHREAD_COND_H */