exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / pthread-cond.c
blob380cdfd3576d04aa9e405b0070d054cfd687d045
1 /* POSIX condition variables.
2 Copyright (C) 2010-2024 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 Paul Eggert, 2010, and Bruno Haible <bruno@clisp.org>, 2019. */
19 #include <config.h>
21 /* Specification. */
22 #include <pthread.h>
24 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
25 # include "windows-thread.h"
26 #else
27 # include <errno.h>
28 # include <limits.h>
29 # include <sys/time.h>
30 # include <time.h>
31 #endif
33 #if ((defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS) || !HAVE_PTHREAD_H
35 int
36 pthread_condattr_init (pthread_condattr_t *attr)
38 *attr = 0;
39 return 0;
42 int
43 pthread_condattr_destroy (_GL_UNUSED pthread_condattr_t *attr)
45 return 0;
48 #endif
50 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
51 /* Use Windows threads. */
53 int
54 pthread_cond_init (pthread_cond_t *cond,
55 _GL_UNUSED const pthread_condattr_t *attr)
57 return glwthread_cond_init (cond);
60 int
61 pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
63 return glwthread_cond_wait (cond, mutex,
64 (int (*) (void *)) pthread_mutex_lock,
65 (int (*) (void *)) pthread_mutex_unlock);
68 int
69 pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
70 const struct timespec *abstime)
72 return glwthread_cond_timedwait (cond, mutex,
73 (int (*) (void *)) pthread_mutex_lock,
74 (int (*) (void *)) pthread_mutex_unlock,
75 abstime);
78 int
79 pthread_cond_signal (pthread_cond_t *cond)
81 return glwthread_cond_signal (cond);
84 int
85 pthread_cond_broadcast (pthread_cond_t *cond)
87 return glwthread_cond_broadcast (cond);
90 int
91 pthread_cond_destroy (pthread_cond_t *cond)
93 return glwthread_cond_destroy (cond);
96 #elif HAVE_PTHREAD_H
97 /* Provide workarounds for POSIX threads. */
99 #else
100 /* Provide a dummy implementation for single-threaded applications. */
103 pthread_cond_init (_GL_UNUSED pthread_cond_t *cond,
104 _GL_UNUSED const pthread_condattr_t *attr)
106 /* COND is never seriously used. */
107 return 0;
111 pthread_cond_wait (_GL_UNUSED pthread_cond_t *cond,
112 _GL_UNUSED pthread_mutex_t *mutex)
114 /* No other thread can signal this condition variable.
115 Wait endlessly. */
116 for (;;)
118 struct timespec duration =
120 .tv_sec = 86400,
121 .tv_nsec = 0
123 nanosleep (&duration, NULL);
128 pthread_cond_timedwait (_GL_UNUSED pthread_cond_t *cond,
129 _GL_UNUSED pthread_mutex_t *mutex,
130 const struct timespec *abstime)
132 /* No other thread can signal this condition variable.
133 Wait until ABSTIME is reached. */
134 for (;;)
136 struct timeval currtime;
137 unsigned long remaining;
139 gettimeofday (&currtime, NULL);
141 if (currtime.tv_sec > abstime->tv_sec)
142 remaining = 0;
143 else
145 unsigned long seconds = abstime->tv_sec - currtime.tv_sec;
146 remaining = seconds * 1000000000;
147 if (remaining / 1000000000 != seconds) /* overflow? */
148 remaining = ULONG_MAX;
149 else
151 long nanoseconds =
152 abstime->tv_nsec - currtime.tv_usec * 1000;
153 if (nanoseconds >= 0)
155 remaining += nanoseconds;
156 if (remaining < nanoseconds) /* overflow? */
157 remaining = ULONG_MAX;
159 else
161 if (remaining >= - nanoseconds)
162 remaining -= (- nanoseconds);
163 else
164 remaining = 0;
168 if (remaining == 0)
169 return ETIMEDOUT;
171 /* Sleep up to REMAINING ns. */
172 struct timespec duration = { .tv_sec = remaining / 1000000000,
173 .tv_nsec = remaining % 1000000000 };
174 nanosleep (&duration, NULL);
179 pthread_cond_signal (_GL_UNUSED pthread_cond_t *cond)
181 /* No threads can currently be blocked on COND. */
182 return 0;
186 pthread_cond_broadcast (_GL_UNUSED pthread_cond_t *cond)
188 /* No threads can currently be blocked on COND. */
189 return 0;
193 pthread_cond_destroy (_GL_UNUSED pthread_cond_t *cond)
195 /* COND is never seriously used. */
196 return 0;
199 #endif