Coverage Report

Created: 2025-01-28 06:58

/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 */