1 /* Condition variables for multithreading.
2 Copyright (C) 2005-2025 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 This file 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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://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
51 /* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, HAVE_THREADS_H. */
52 #if !_GL_CONFIG_H_INCLUDED
53 #error "Please include config.h first."
60 #include "glthread/lock.h"
62 #if !defined c11_threads_in_use
63 # if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
64 # define c11_threads_in_use() 1
65 # elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
67 # pragma weak thrd_exit
68 # define c11_threads_in_use() (thrd_exit != NULL)
70 # define c11_threads_in_use() 0
74 _GL_INLINE_HEADER_BEGIN
75 #ifndef _GLTHREAD_COND_INLINE
76 # define _GLTHREAD_COND_INLINE _GL_INLINE
79 /* ========================================================================= */
81 #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
83 /* Use the ISO C threads library. */
91 /* -------------------------- gl_cond_t datatype -------------------------- */
95 int volatile init_needed
;
97 void (*init_func
) (void);
101 # define gl_cond_define(STORAGECLASS, NAME) \
102 STORAGECLASS gl_cond_t NAME;
103 # define gl_cond_define_initialized(STORAGECLASS, NAME) \
104 static void _atomic_init_##NAME (void); \
105 STORAGECLASS gl_cond_t NAME = \
106 { 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
107 static void _atomic_init_##NAME (void) \
109 if (glthread_cond_init (&(NAME))) \
112 extern int glthread_cond_init (gl_cond_t
*condition
);
113 extern int glthread_cond_wait (gl_cond_t
*condition
, gl_lock_t
*lock
);
114 extern int glthread_cond_timedwait (gl_cond_t
*condition
, gl_lock_t
*lock
,
115 const struct timespec
*abstime
);
116 extern int glthread_cond_signal (gl_cond_t
*condition
);
117 extern int glthread_cond_broadcast (gl_cond_t
*condition
);
118 extern int glthread_cond_destroy (gl_cond_t
*condition
);
126 /* ========================================================================= */
128 #if USE_POSIX_THREADS
130 /* Use the POSIX threads library. */
132 # include <pthread.h>
138 # if PTHREAD_IN_USE_DETECTION_HARD
140 /* The pthread_in_use() detection needs to be done at runtime. */
141 # define pthread_in_use() \
143 extern int glthread_in_use (void);
147 # if USE_POSIX_THREADS_WEAK
149 /* Use weak references to the POSIX threads library. */
151 /* Weak references avoid dragging in external libraries if the other parts
152 of the program don't use them. Here we use them, because we don't want
153 every program that uses libintl to depend on libpthread. This assumes
154 that libpthread would not be loaded after libintl; i.e. if libintl is
155 loaded first, by an executable that does not depend on libpthread, and
156 then a module is dynamically loaded that depends on libpthread, libintl
157 will not be multithread-safe. */
159 /* The way to test at runtime whether libpthread is present is to test
160 whether a function pointer's value, such as &pthread_mutex_init, is
161 non-NULL. However, some versions of GCC have a bug through which, in
162 PIC mode, &foo != NULL always evaluates to true if there is a direct
163 call to foo(...) in the same function. To avoid this, we test the
164 address of a function in libpthread that we don't use. */
166 # pragma weak pthread_cond_init
167 # pragma weak pthread_cond_wait
168 # pragma weak pthread_cond_timedwait
169 # pragma weak pthread_cond_signal
170 # pragma weak pthread_cond_broadcast
171 # pragma weak pthread_cond_destroy
172 # ifndef pthread_self
173 # pragma weak pthread_self
176 # if !PTHREAD_IN_USE_DETECTION_HARD
177 # pragma weak pthread_mutexattr_gettype
178 # define pthread_in_use() \
179 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
184 # if !PTHREAD_IN_USE_DETECTION_HARD
185 # define pthread_in_use() 1
190 /* -------------------------- gl_cond_t datatype -------------------------- */
192 typedef pthread_cond_t gl_cond_t
;
193 # define gl_cond_define(STORAGECLASS, NAME) \
194 STORAGECLASS gl_cond_t NAME;
195 # define gl_cond_define_initialized(STORAGECLASS, NAME) \
196 STORAGECLASS gl_cond_t NAME = gl_cond_initializer;
197 # define gl_cond_initializer \
198 PTHREAD_COND_INITIALIZER
199 # define glthread_cond_init(COND) \
200 (pthread_in_use () ? pthread_cond_init (COND, NULL) : 0)
201 # define glthread_cond_wait(COND, LOCK) \
202 (pthread_in_use () ? pthread_cond_wait (COND, LOCK) : 0)
203 # define glthread_cond_timedwait(COND, LOCK, ABSTIME) \
204 (pthread_in_use () ? pthread_cond_timedwait (COND, LOCK, ABSTIME) : 0)
205 # define glthread_cond_signal(COND) \
206 (pthread_in_use () ? pthread_cond_signal (COND) : 0)
207 # define glthread_cond_broadcast(COND) \
208 (pthread_in_use () ? pthread_cond_broadcast (COND) : 0)
209 # define glthread_cond_destroy(COND) \
210 (pthread_in_use () ? pthread_cond_destroy (COND) : 0)
218 /* ========================================================================= */
220 #if USE_WINDOWS_THREADS
222 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
223 # include <windows.h>
225 # include "windows-cond.h"
231 /* -------------------------- gl_cond_t datatype -------------------------- */
233 typedef glwthread_cond_t gl_cond_t
;
234 # define gl_cond_define(STORAGECLASS, NAME) \
235 STORAGECLASS gl_cond_t NAME;
236 # define gl_cond_define_initialized(STORAGECLASS, NAME) \
237 STORAGECLASS gl_cond_t NAME = gl_cond_initializer;
238 # define gl_cond_initializer \
240 # define glthread_cond_init(COND) \
241 glwthread_cond_init (COND)
242 # define glthread_cond_wait(COND, LOCK) \
243 glwthread_cond_wait (COND, LOCK, \
244 (int (*) (void *)) glwthread_mutex_lock, \
245 (int (*) (void *)) glwthread_mutex_unlock)
246 # define glthread_cond_timedwait(COND, LOCK, ABSTIME) \
247 glwthread_cond_timedwait (COND, LOCK, \
248 (int (*) (void *)) glwthread_mutex_lock, \
249 (int (*) (void *)) glwthread_mutex_unlock, \
251 # define glthread_cond_signal(COND) \
252 glwthread_cond_signal (COND)
253 # define glthread_cond_broadcast(COND) \
254 glwthread_cond_broadcast (COND)
255 # define glthread_cond_destroy(COND) \
256 glwthread_cond_destroy (COND)
264 /* ========================================================================= */
266 #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
268 /* Provide dummy implementation if threads are not supported. */
270 typedef int gl_cond_t
;
271 # define gl_cond_define(STORAGECLASS, NAME)
272 # define gl_cond_define_initialized(STORAGECLASS, NAME)
273 # define glthread_cond_init(COND) 0
274 # define glthread_cond_wait(COND, LOCK) 0
275 # define glthread_cond_timedwait(COND, LOCK, ABSTIME) 0
276 # define glthread_cond_signal(COND) 0
277 # define glthread_cond_broadcast(COND) 0
278 # define glthread_cond_destroy(COND) 0
282 /* ========================================================================= */
284 /* Macros with built-in error handling. */
290 #define gl_cond_init(COND) \
293 if (glthread_cond_init (&COND)) \
297 #define gl_cond_wait(COND, LOCK) \
300 if (glthread_cond_wait (&COND, &LOCK)) \
304 #define gl_cond_timedwait(COND, LOCK, ABSTIME) \
305 gl_cond_timedwait_func (&COND, &LOCK, ABSTIME)
306 _GLTHREAD_COND_INLINE
bool
307 gl_cond_timedwait_func (gl_cond_t
*cond
, gl_lock_t
*lock
, struct timespec
*abstime
)
309 int err
= glthread_cond_timedwait (cond
, lock
, abstime
);
310 if (err
== ETIMEDOUT
)
316 #define gl_cond_signal(COND) \
319 if (glthread_cond_signal (&COND)) \
323 #define gl_cond_broadcast(COND) \
326 if (glthread_cond_broadcast (&COND)) \
330 #define gl_cond_destroy(COND) \
333 if (glthread_cond_destroy (&COND)) \
342 _GL_INLINE_HEADER_END
344 #endif /* _GLTHREAD_COND_H */