/src/wget2/lib/glthread/cond.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* Condition variables for multithreading. |
2 | | Copyright (C) 2005-2025 Free Software Foundation, Inc. |
3 | | |
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. |
8 | | |
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. |
13 | | |
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/>. */ |
16 | | |
17 | | /* Written by Yoann Vandoorselaere <yoann@prelude-ids.org>, 2008. |
18 | | Based on Bruno Haible <bruno@clisp.org> lock.h */ |
19 | | |
20 | | /* |
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. |
26 | | |
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); |
45 | | */ |
46 | | |
47 | | |
48 | | #ifndef _GLTHREAD_COND_H |
49 | | #define _GLTHREAD_COND_H |
50 | | |
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 |
55 | | |
56 | | #include <errno.h> |
57 | | #include <stdlib.h> |
58 | | #include <time.h> |
59 | | |
60 | | #include "glthread/lock.h" |
61 | | |
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 |
73 | | |
74 | | _GL_INLINE_HEADER_BEGIN |
75 | | #ifndef _GLTHREAD_COND_INLINE |
76 | | # define _GLTHREAD_COND_INLINE _GL_INLINE |
77 | | #endif |
78 | | |
79 | | /* ========================================================================= */ |
80 | | |
81 | | #if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS |
82 | | |
83 | | /* Use the ISO C threads library. */ |
84 | | |
85 | | # include <threads.h> |
86 | | |
87 | | # ifdef __cplusplus |
88 | | extern "C" { |
89 | | # endif |
90 | | |
91 | | /* -------------------------- gl_cond_t datatype -------------------------- */ |
92 | | |
93 | | typedef struct |
94 | | { |
95 | | int volatile init_needed; |
96 | | once_flag init_once; |
97 | | void (*init_func) (void); |
98 | | cnd_t condition; |
99 | | } |
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) \ |
108 | | { \ |
109 | | if (glthread_cond_init (&(NAME))) \ |
110 | | abort (); \ |
111 | | } |
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); |
119 | | |
120 | | # ifdef __cplusplus |
121 | | } |
122 | | # endif |
123 | | |
124 | | #endif |
125 | | |
126 | | /* ========================================================================= */ |
127 | | |
128 | | #if USE_POSIX_THREADS |
129 | | |
130 | | /* Use the POSIX threads library. */ |
131 | | |
132 | | # include <pthread.h> |
133 | | |
134 | | # ifdef __cplusplus |
135 | | extern "C" { |
136 | | # endif |
137 | | |
138 | | # if PTHREAD_IN_USE_DETECTION_HARD |
139 | | |
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); |
144 | | |
145 | | # endif |
146 | | |
147 | | # if USE_POSIX_THREADS_WEAK |
148 | | |
149 | | /* Use weak references to the POSIX threads library. */ |
150 | | |
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. */ |
158 | | |
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. */ |
165 | | |
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 |
175 | | |
176 | | # if !PTHREAD_IN_USE_DETECTION_HARD |
177 | | # pragma weak pthread_mutexattr_gettype |
178 | | # define pthread_in_use() \ |
179 | 9.18k | (pthread_mutexattr_gettype != NULL || c11_threads_in_use ()) |
180 | | # endif |
181 | | |
182 | | # else |
183 | | |
184 | | # if !PTHREAD_IN_USE_DETECTION_HARD |
185 | | # define pthread_in_use() 1 |
186 | | # endif |
187 | | |
188 | | # endif |
189 | | |
190 | | /* -------------------------- gl_cond_t datatype -------------------------- */ |
191 | | |
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 | 0 | (pthread_in_use () ? pthread_cond_init (COND, NULL) : 0) |
201 | | # define glthread_cond_wait(COND, LOCK) \ |
202 | 0 | (pthread_in_use () ? pthread_cond_wait (COND, LOCK) : 0) |
203 | | # define glthread_cond_timedwait(COND, LOCK, ABSTIME) \ |
204 | 0 | (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 | 0 | (pthread_in_use () ? pthread_cond_broadcast (COND) : 0) |
209 | | # define glthread_cond_destroy(COND) \ |
210 | 0 | (pthread_in_use () ? pthread_cond_destroy (COND) : 0) |
211 | | |
212 | | # ifdef __cplusplus |
213 | | } |
214 | | # endif |
215 | | |
216 | | #endif |
217 | | |
218 | | /* ========================================================================= */ |
219 | | |
220 | | #if USE_WINDOWS_THREADS |
221 | | |
222 | | # define WIN32_LEAN_AND_MEAN /* avoid including junk */ |
223 | | # include <windows.h> |
224 | | |
225 | | # include "windows-cond.h" |
226 | | |
227 | | # ifdef __cplusplus |
228 | | extern "C" { |
229 | | # endif |
230 | | |
231 | | /* -------------------------- gl_cond_t datatype -------------------------- */ |
232 | | |
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) |
257 | | |
258 | | # ifdef __cplusplus |
259 | | } |
260 | | # endif |
261 | | |
262 | | #endif |
263 | | |
264 | | /* ========================================================================= */ |
265 | | |
266 | | #if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS) |
267 | | |
268 | | /* Provide dummy implementation if threads are not supported. */ |
269 | | |
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 |
279 | | |
280 | | #endif |
281 | | |
282 | | /* ========================================================================= */ |
283 | | |
284 | | /* Macros with built-in error handling. */ |
285 | | |
286 | | #ifdef __cplusplus |
287 | | extern "C" { |
288 | | #endif |
289 | | |
290 | | #define gl_cond_init(COND) \ |
291 | | do \ |
292 | | { \ |
293 | | if (glthread_cond_init (&COND)) \ |
294 | | abort (); \ |
295 | | } \ |
296 | | while (0) |
297 | | #define gl_cond_wait(COND, LOCK) \ |
298 | | do \ |
299 | | { \ |
300 | | if (glthread_cond_wait (&COND, &LOCK)) \ |
301 | | abort (); \ |
302 | | } \ |
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) |
308 | 0 | { |
309 | 0 | int err = glthread_cond_timedwait (cond, lock, abstime); |
310 | 0 | if (err == ETIMEDOUT) |
311 | 0 | return true; |
312 | 0 | if (err != 0) |
313 | 0 | abort (); |
314 | 0 | return false; |
315 | 0 | } |
316 | | #define gl_cond_signal(COND) \ |
317 | | do \ |
318 | | { \ |
319 | | if (glthread_cond_signal (&COND)) \ |
320 | | abort (); \ |
321 | | } \ |
322 | | while (0) |
323 | | #define gl_cond_broadcast(COND) \ |
324 | | do \ |
325 | | { \ |
326 | | if (glthread_cond_broadcast (&COND)) \ |
327 | | abort (); \ |
328 | | } \ |
329 | | while (0) |
330 | | #define gl_cond_destroy(COND) \ |
331 | | do \ |
332 | | { \ |
333 | | if (glthread_cond_destroy (&COND)) \ |
334 | | abort (); \ |
335 | | } \ |
336 | | while (0) |
337 | | |
338 | | #ifdef __cplusplus |
339 | | } |
340 | | #endif |
341 | | |
342 | | _GL_INLINE_HEADER_END |
343 | | |
344 | | #endif /* _GLTHREAD_COND_H */ |