1 /* Condition variables for multithreading.
2 Copyright (C) 2005-2012 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, see <http://www.gnu.org/licenses/>. */
17 /* Written by Yoann Vandoorselaere <yoann@prelude-ids.org>, 2008.
18 Based on Bruno Haible <bruno@clisp.org> lock.h */
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
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);
48 #ifndef _GLTHREAD_COND_H
49 #define _GLTHREAD_COND_H
56 #include "glthread/lock.h"
58 /* ========================================================================= */
62 /* Use the POSIX threads library. */
70 # if PTHREAD_IN_USE_DETECTION_HARD
72 /* The pthread_in_use() detection needs to be done at runtime. */
73 # define pthread_in_use() \
75 extern int glthread_in_use (void);
79 # if USE_POSIX_THREADS_WEAK
81 /* Use weak references to the POSIX threads library. */
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. */
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. */
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
108 # if !PTHREAD_IN_USE_DETECTION_HARD
109 # pragma weak pthread_cancel
110 # define pthread_in_use() (pthread_cancel != NULL)
115 # if !PTHREAD_IN_USE_DETECTION_HARD
116 # define pthread_in_use() 1
121 /* -------------------------- gl_cond_t datatype -------------------------- */
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)
149 /* ========================================================================= */
153 /* Use the GNU Pth threads library. */
161 # if USE_PTH_THREADS_WEAK
163 /* Use weak references to the GNU Pth threads library. */
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
171 # pragma weak pth_cancel
172 # define pth_in_use() (pth_cancel != NULL)
176 # define pth_in_use() 1
180 /* -------------------------- gl_cond_t datatype -------------------------- */
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 \
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);
208 /* ========================================================================= */
210 #if USE_SOLARIS_THREADS
212 /* Use the old Solaris threads library. */
221 # if USE_SOLARIS_THREADS_WEAK
223 /* Use weak references to the old Solaris threads library. */
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)
236 # define thread_in_use() 1
240 /* -------------------------- gl_cond_t datatype -------------------------- */
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 \
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);
269 /* ========================================================================= */
271 #if USE_WINDOWS_THREADS
273 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
274 # include <windows.h>
280 /* -------------------------- gl_cond_t datatype -------------------------- */
282 struct gl_waitqueue_link
284 struct gl_waitqueue_link *wql_next;
285 struct gl_waitqueue_link *wql_prev;
289 struct gl_waitqueue_link wq_list; /* circular list of waiting threads */
291 gl_linked_waitqueue_t;
294 gl_spinlock_t guard; /* protects the initialization */
295 CRITICAL_SECTION lock; /* protects the remaining fields */
296 gl_linked_waitqueue_t waiters; /* waiting threads */
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 \
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);
330 /* ========================================================================= */
332 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
334 /* Provide dummy implementation if threads are not supported. */
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
348 /* ========================================================================= */
350 /* Macros with built-in error handling. */
356 #define gl_cond_init(COND) \
359 if (glthread_cond_init (&COND)) \
363 #define gl_cond_wait(COND, LOCK) \
366 if (glthread_cond_wait (&COND, &LOCK)) \
370 #define gl_cond_timedwait(COND, LOCK, ABSTIME) \
371 gl_cond_timedwait_func (&COND, &LOCK, ABSTIME)
373 gl_cond_timedwait_func (gl_cond_t *cond, gl_lock_t *lock, struct timespec *abstime)
375 int err = glthread_cond_timedwait (cond, lock, abstime);
376 if (err == ETIMEDOUT)
382 #define gl_cond_signal(COND) \
385 if (glthread_cond_signal (&COND)) \
389 #define gl_cond_broadcast(COND) \
392 if (glthread_cond_broadcast (&COND)) \
396 #define gl_cond_destroy(COND) \
399 if (glthread_cond_destroy (&COND)) \
408 #endif /* _GLTHREAD_COND_H */