1 /* POSIX condition variables.
2    Copyright (C) 2010-2020 Free Software Foundation, Inc.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    This program 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 General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, see <https://www.gnu.org/licenses/>.  */
16 
17 /* Written by Paul Eggert, 2010, and Bruno Haible <bruno@clisp.org>, 2019.  */
18 
19 #include <config.h>
20 
21 /* Specification.  */
22 #include <pthread.h>
23 
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
32 
33 #if ((defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS) || !HAVE_PTHREAD_H
34 
35 int
pthread_condattr_init(pthread_condattr_t * attr)36 pthread_condattr_init (pthread_condattr_t *attr)
37 {
38   *attr = 0;
39   return 0;
40 }
41 
42 int
pthread_condattr_destroy(pthread_condattr_t * attr _GL_UNUSED)43 pthread_condattr_destroy (pthread_condattr_t *attr _GL_UNUSED)
44 {
45   return 0;
46 }
47 
48 #endif
49 
50 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
51 /* Use Windows threads.  */
52 
53 int
pthread_cond_init(pthread_cond_t * cond,const pthread_condattr_t * attr _GL_UNUSED)54 pthread_cond_init (pthread_cond_t *cond,
55                    const pthread_condattr_t *attr _GL_UNUSED)
56 {
57   return glwthread_cond_init (cond);
58 }
59 
60 int
pthread_cond_wait(pthread_cond_t * cond,pthread_mutex_t * mutex)61 pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
62 {
63   return glwthread_cond_wait (cond, mutex,
64                               (int (*) (void *)) pthread_mutex_lock,
65                               (int (*) (void *)) pthread_mutex_unlock);
66 }
67 
68 int
pthread_cond_timedwait(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * abstime)69 pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
70                         const struct timespec *abstime)
71 {
72   return glwthread_cond_timedwait (cond, mutex,
73                                    (int (*) (void *)) pthread_mutex_lock,
74                                    (int (*) (void *)) pthread_mutex_unlock,
75                                    abstime);
76 }
77 
78 int
pthread_cond_signal(pthread_cond_t * cond)79 pthread_cond_signal (pthread_cond_t *cond)
80 {
81   return glwthread_cond_signal (cond);
82 }
83 
84 int
pthread_cond_broadcast(pthread_cond_t * cond)85 pthread_cond_broadcast (pthread_cond_t *cond)
86 {
87   return glwthread_cond_broadcast (cond);
88 }
89 
90 int
pthread_cond_destroy(pthread_cond_t * cond)91 pthread_cond_destroy (pthread_cond_t *cond)
92 {
93   return glwthread_cond_destroy (cond);
94 }
95 
96 #elif HAVE_PTHREAD_H
97 /* Provide workarounds for POSIX threads.  */
98 
99 #else
100 /* Provide a dummy implementation for single-threaded applications.  */
101 
102 int
pthread_cond_init(pthread_cond_t * cond _GL_UNUSED,const pthread_condattr_t * attr _GL_UNUSED)103 pthread_cond_init (pthread_cond_t *cond _GL_UNUSED,
104                    const pthread_condattr_t *attr _GL_UNUSED)
105 {
106   /* COND is never seriously used.  */
107   return 0;
108 }
109 
110 int
pthread_cond_wait(pthread_cond_t * cond _GL_UNUSED,pthread_mutex_t * mutex _GL_UNUSED)111 pthread_cond_wait (pthread_cond_t *cond _GL_UNUSED,
112                    pthread_mutex_t *mutex _GL_UNUSED)
113 {
114   /* No other thread can signal this condition variable.
115      Wait endlessly.  */
116   for (;;)
117     {
118       struct timespec duration;
119 
120       duration.tv_sec = 86400;
121       duration.tv_usec = 0;
122       nanosleep (&duration, NULL);
123     }
124 }
125 
126 int
pthread_cond_timedwait(pthread_cond_t * cond _GL_UNUSED,pthread_mutex_t * mutex _GL_UNUSED,const struct timespec * abstime)127 pthread_cond_timedwait (pthread_cond_t *cond _GL_UNUSED,
128                         pthread_mutex_t *mutex _GL_UNUSED,
129                         const struct timespec *abstime)
130 {
131   /* No other thread can signal this condition variable.
132      Wait until ABSTIME is reached.  */
133   for (;;)
134     {
135       struct timeval currtime;
136       unsigned long remaining;
137       struct timespec duration;
138 
139       gettimeofday (&currtime, NULL);
140 
141       if (currtime.tv_sec > abstime->tv_sec)
142         remaining = 0;
143       else
144         {
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
150             {
151               long nanoseconds =
152                 abstime->tv_nsec - currtime.tv_usec * 1000;
153               if (nanoseconds >= 0)
154                 {
155                   remaining += nanoseconds;
156                   if (remaining < nanoseconds) /* overflow? */
157                     remaining = ULONG_MAX;
158                 }
159               else
160                 {
161                   if (remaining >= - nanoseconds)
162                     remaining -= (- nanoseconds);
163                   else
164                     remaining = 0;
165                 }
166             }
167         }
168       if (remaining == 0)
169         return ETIMEDOUT;
170 
171       /* Sleep up to REMAINING ns.  */
172       duration.tv_sec = remaining / 1000000000;
173       duration.tv_nsec = remaining % 1000000000;
174       nanosleep (&duration, NULL);
175     }
176 }
177 
178 int
pthread_cond_signal(pthread_cond_t * cond _GL_UNUSED)179 pthread_cond_signal (pthread_cond_t *cond _GL_UNUSED)
180 {
181   /* No threads can currently be blocked on COND.  */
182   return 0;
183 }
184 
185 int
pthread_cond_broadcast(pthread_cond_t * cond _GL_UNUSED)186 pthread_cond_broadcast (pthread_cond_t *cond _GL_UNUSED)
187 {
188   /* No threads can currently be blocked on COND.  */
189   return 0;
190 }
191 
192 int
pthread_cond_destroy(pthread_cond_t * cond _GL_UNUSED)193 pthread_cond_destroy (pthread_cond_t *cond _GL_UNUSED)
194 {
195   /* COND is never seriously used.  */
196   return 0;
197 }
198 
199 #endif
200