1 /* Condition variables for multithreading.
2 Copyright (C) 2005-2013 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 _GL_INLINE_HEADER_BEGIN
59 #ifndef _GLTHREAD_COND_INLINE
60 # define _GLTHREAD_COND_INLINE _GL_INLINE
63 /* ========================================================================= */
67 /* Use the POSIX threads library. */
75 # if PTHREAD_IN_USE_DETECTION_HARD
77 /* The pthread_in_use() detection needs to be done at runtime. */
78 # define pthread_in_use() \
80 extern int glthread_in_use (void);
84 # if USE_POSIX_THREADS_WEAK
86 /* Use weak references to the POSIX threads library. */
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. */
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. */
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
113 # if !PTHREAD_IN_USE_DETECTION_HARD
114 # pragma weak pthread_cancel
115 # define pthread_in_use() (pthread_cancel != NULL)
120 # if !PTHREAD_IN_USE_DETECTION_HARD
121 # define pthread_in_use() 1
126 /* -------------------------- gl_cond_t datatype -------------------------- */
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)
154 /* ========================================================================= */
158 /* Use the GNU Pth threads library. */
166 # if USE_PTH_THREADS_WEAK
168 /* Use weak references to the GNU Pth threads library. */
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
176 # pragma weak pth_cancel
177 # define pth_in_use() (pth_cancel != NULL)
181 # define pth_in_use() 1
185 /* -------------------------- gl_cond_t datatype -------------------------- */
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 \
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);
213 /* ========================================================================= */
215 #if USE_SOLARIS_THREADS
217 /* Use the old Solaris threads library. */
226 # if USE_SOLARIS_THREADS_WEAK
228 /* Use weak references to the old Solaris threads library. */
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)
241 # define thread_in_use() 1
245 /* -------------------------- gl_cond_t datatype -------------------------- */
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 \
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);
274 /* ========================================================================= */
276 #if USE_WINDOWS_THREADS
278 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
279 # include <windows.h>
285 /* -------------------------- gl_cond_t datatype -------------------------- */
287 struct gl_waitqueue_link
289 struct gl_waitqueue_link *wql_next;
290 struct gl_waitqueue_link *wql_prev;
294 struct gl_waitqueue_link wq_list; /* circular list of waiting threads */
296 gl_linked_waitqueue_t;
299 gl_spinlock_t guard; /* protects the initialization */
300 CRITICAL_SECTION lock; /* protects the remaining fields */
301 gl_linked_waitqueue_t waiters; /* waiting threads */
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 \
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);
335 /* ========================================================================= */
337 #if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WINDOWS_THREADS)
339 /* Provide dummy implementation if threads are not supported. */
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
353 /* ========================================================================= */
355 /* Macros with built-in error handling. */
361 #define gl_cond_init(COND) \
364 if (glthread_cond_init (&COND)) \
368 #define gl_cond_wait(COND, LOCK) \
371 if (glthread_cond_wait (&COND, &LOCK)) \
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)
380 int err = glthread_cond_timedwait (cond, lock, abstime);
381 if (err == ETIMEDOUT)
387 #define gl_cond_signal(COND) \
390 if (glthread_cond_signal (&COND)) \
394 #define gl_cond_broadcast(COND) \
397 if (glthread_cond_broadcast (&COND)) \
401 #define gl_cond_destroy(COND) \
404 if (glthread_cond_destroy (&COND)) \
413 _GL_INLINE_HEADER_END
415 #endif /* _GLTHREAD_COND_H */