Fix last ChangeLog entry.
[gnulib.git] / lib / glthread / cond.h
blob6ef8a5700ee7d3e24e14ae5a4d5564c4e9c6b6a8
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
25 waiting for them.
27 Condition variable:
28 Type: gl_cond_t
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."
54 #endif
56 #include <errno.h>
57 #include <stdlib.h>
58 #include <time.h>
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
66 # include <threads.h>
67 # pragma weak thrd_exit
68 # define c11_threads_in_use() (thrd_exit != NULL)
69 # else
70 # define c11_threads_in_use() 0
71 # endif
72 #endif
74 _GL_INLINE_HEADER_BEGIN
75 #ifndef _GLTHREAD_COND_INLINE
76 # define _GLTHREAD_COND_INLINE _GL_INLINE
77 #endif
79 /* ========================================================================= */
81 #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
83 /* Use the ISO C threads library. */
85 # include <threads.h>
87 # ifdef __cplusplus
88 extern "C" {
89 # endif
91 /* -------------------------- gl_cond_t datatype -------------------------- */
93 typedef struct
95 int volatile init_needed;
96 once_flag init_once;
97 void (*init_func) (void);
98 cnd_t condition;
100 gl_cond_t;
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))) \
110 abort (); \
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);
120 # ifdef __cplusplus
122 # endif
124 #endif
126 /* ========================================================================= */
128 #if USE_POSIX_THREADS
130 /* Use the POSIX threads library. */
132 # include <pthread.h>
134 # ifdef __cplusplus
135 extern "C" {
136 # endif
138 # if PTHREAD_IN_USE_DETECTION_HARD
140 /* The pthread_in_use() detection needs to be done at runtime. */
141 # define pthread_in_use() \
142 glthread_in_use ()
143 extern int glthread_in_use (void);
145 # endif
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
174 # endif
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 ())
180 # endif
182 # else
184 # if !PTHREAD_IN_USE_DETECTION_HARD
185 # define pthread_in_use() 1
186 # endif
188 # endif
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)
212 # ifdef __cplusplus
214 # endif
216 #endif
218 /* ========================================================================= */
220 #if USE_WINDOWS_THREADS
222 # define WIN32_LEAN_AND_MEAN /* avoid including junk */
223 # include <windows.h>
225 # include "windows-cond.h"
227 # ifdef __cplusplus
228 extern "C" {
229 # endif
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 \
239 GLWTHREAD_COND_INIT
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, \
250 ABSTIME)
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)
258 # ifdef __cplusplus
260 # endif
262 #endif
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
280 #endif
282 /* ========================================================================= */
284 /* Macros with built-in error handling. */
286 #ifdef __cplusplus
287 extern "C" {
288 #endif
290 #define gl_cond_init(COND) \
291 do \
293 if (glthread_cond_init (&COND)) \
294 abort (); \
296 while (0)
297 #define gl_cond_wait(COND, LOCK) \
298 do \
300 if (glthread_cond_wait (&COND, &LOCK)) \
301 abort (); \
303 while (0)
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)
311 return true;
312 if (err != 0)
313 abort ();
314 return false;
316 #define gl_cond_signal(COND) \
317 do \
319 if (glthread_cond_signal (&COND)) \
320 abort (); \
322 while (0)
323 #define gl_cond_broadcast(COND) \
324 do \
326 if (glthread_cond_broadcast (&COND)) \
327 abort (); \
329 while (0)
330 #define gl_cond_destroy(COND) \
331 do \
333 if (glthread_cond_destroy (&COND)) \
334 abort (); \
336 while (0)
338 #ifdef __cplusplus
340 #endif
342 _GL_INLINE_HEADER_END
344 #endif /* _GLTHREAD_COND_H */