havelib: Fix for Solaris 11 OpenIndiana and Solaris 11 OmniOS.
[gnulib.git] / lib / nanosleep.c
blob123c66bfa950dab8a5999c8f2d914bac15d87a47
1 /* Provide a replacement for the POSIX nanosleep function.
3 Copyright (C) 1999-2000, 2002, 2004-2020 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* written by Jim Meyering
19 and Bruno Haible for the native Windows part */
21 #include <config.h>
23 #include <time.h>
25 #include "intprops.h"
26 #include "sig-handler.h"
27 #include "verify.h"
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <sys/types.h>
32 #include <sys/select.h>
33 #include <signal.h>
35 #include <sys/time.h>
36 #include <errno.h>
38 #include <unistd.h>
41 enum { BILLION = 1000 * 1000 * 1000 };
43 #if HAVE_BUG_BIG_NANOSLEEP
45 int
46 nanosleep (const struct timespec *requested_delay,
47 struct timespec *remaining_delay)
48 # undef nanosleep
50 /* nanosleep mishandles large sleeps due to internal overflow problems.
51 The worst known case of this is Linux 2.6.9 with glibc 2.3.4, which
52 can't sleep more than 24.85 days (2^31 milliseconds). Similarly,
53 cygwin 1.5.x, which can't sleep more than 49.7 days (2^32 milliseconds).
54 Solve this by breaking the sleep up into smaller chunks. */
56 if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
58 errno = EINVAL;
59 return -1;
63 /* Verify that time_t is large enough. */
64 verify (TYPE_MAXIMUM (time_t) / 24 / 24 / 60 / 60);
65 const time_t limit = 24 * 24 * 60 * 60;
66 time_t seconds = requested_delay->tv_sec;
67 struct timespec intermediate;
68 intermediate.tv_nsec = requested_delay->tv_nsec;
70 while (limit < seconds)
72 int result;
73 intermediate.tv_sec = limit;
74 result = nanosleep (&intermediate, remaining_delay);
75 seconds -= limit;
76 if (result)
78 if (remaining_delay)
79 remaining_delay->tv_sec += seconds;
80 return result;
82 intermediate.tv_nsec = 0;
84 intermediate.tv_sec = seconds;
85 return nanosleep (&intermediate, remaining_delay);
89 #elif defined _WIN32 && ! defined __CYGWIN__
90 /* Native Windows platforms. */
92 # define WIN32_LEAN_AND_MEAN
93 # include <windows.h>
95 /* The Windows API function Sleep() has a resolution of about 15 ms and takes
96 at least 5 ms to execute. We use this function for longer time periods.
97 Additionally, we use busy-looping over short time periods, to get a
98 resolution of about 0.01 ms. In order to measure such short timespans,
99 we use the QueryPerformanceCounter() function. */
102 nanosleep (const struct timespec *requested_delay,
103 struct timespec *remaining_delay)
105 static bool initialized;
106 /* Number of performance counter increments per nanosecond,
107 or zero if it could not be determined. */
108 static double ticks_per_nanosecond;
110 if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
112 errno = EINVAL;
113 return -1;
116 /* For requested delays of one second or more, 15ms resolution is
117 sufficient. */
118 if (requested_delay->tv_sec == 0)
120 if (!initialized)
122 /* Initialize ticks_per_nanosecond. */
123 LARGE_INTEGER ticks_per_second;
125 if (QueryPerformanceFrequency (&ticks_per_second))
126 ticks_per_nanosecond =
127 (double) ticks_per_second.QuadPart / 1000000000.0;
129 initialized = true;
131 if (ticks_per_nanosecond)
133 /* QueryPerformanceFrequency worked. We can use
134 QueryPerformanceCounter. Use a combination of Sleep and
135 busy-looping. */
136 /* Number of milliseconds to pass to the Sleep function.
137 Since Sleep can take up to 8 ms less or 8 ms more than requested
138 (or maybe more if the system is loaded), we subtract 10 ms. */
139 int sleep_millis = (int) requested_delay->tv_nsec / 1000000 - 10;
140 /* Determine how many ticks to delay. */
141 LONGLONG wait_ticks = requested_delay->tv_nsec * ticks_per_nanosecond;
142 /* Start. */
143 LARGE_INTEGER counter_before;
144 if (QueryPerformanceCounter (&counter_before))
146 /* Wait until the performance counter has reached this value.
147 We don't need to worry about overflow, because the performance
148 counter is reset at reboot, and with a frequency of 3.6E6
149 ticks per second 63 bits suffice for over 80000 years. */
150 LONGLONG wait_until = counter_before.QuadPart + wait_ticks;
151 /* Use Sleep for the longest part. */
152 if (sleep_millis > 0)
153 Sleep (sleep_millis);
154 /* Busy-loop for the rest. */
155 for (;;)
157 LARGE_INTEGER counter_after;
158 if (!QueryPerformanceCounter (&counter_after))
159 /* QueryPerformanceCounter failed, but succeeded earlier.
160 Should not happen. */
161 break;
162 if (counter_after.QuadPart >= wait_until)
163 /* The requested time has elapsed. */
164 break;
166 goto done;
170 /* Implementation for long delays and as fallback. */
171 Sleep (requested_delay->tv_sec * 1000 + requested_delay->tv_nsec / 1000000);
173 done:
174 /* Sleep is not interruptible. So there is no remaining delay. */
175 if (remaining_delay != NULL)
177 remaining_delay->tv_sec = 0;
178 remaining_delay->tv_nsec = 0;
180 return 0;
183 #else
184 /* Unix platforms lacking nanosleep. */
186 /* Some systems (MSDOS) don't have SIGCONT.
187 Using SIGTERM here turns the signal-handling code below
188 into a no-op on such systems. */
189 # ifndef SIGCONT
190 # define SIGCONT SIGTERM
191 # endif
193 static sig_atomic_t volatile suspended;
195 /* Handle SIGCONT. */
197 static _GL_ASYNC_SAFE void
198 sighandler (int sig)
200 suspended = 1;
203 /* Suspend execution for at least *TS_DELAY seconds. */
205 static int
206 my_usleep (const struct timespec *ts_delay)
208 struct timeval tv_delay;
209 tv_delay.tv_sec = ts_delay->tv_sec;
210 tv_delay.tv_usec = (ts_delay->tv_nsec + 999) / 1000;
211 if (tv_delay.tv_usec == 1000000)
213 if (tv_delay.tv_sec == TYPE_MAXIMUM (time_t))
214 tv_delay.tv_usec = 1000000 - 1; /* close enough */
215 else
217 tv_delay.tv_sec++;
218 tv_delay.tv_usec = 0;
221 return select (0, NULL, NULL, NULL, &tv_delay);
224 /* Suspend execution for at least *REQUESTED_DELAY seconds. The
225 *REMAINING_DELAY part isn't implemented yet. */
228 nanosleep (const struct timespec *requested_delay,
229 struct timespec *remaining_delay)
231 static bool initialized;
233 if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
235 errno = EINVAL;
236 return -1;
239 /* set up sig handler */
240 if (! initialized)
242 struct sigaction oldact;
244 sigaction (SIGCONT, NULL, &oldact);
245 if (get_handler (&oldact) != SIG_IGN)
247 struct sigaction newact;
249 newact.sa_handler = sighandler;
250 sigemptyset (&newact.sa_mask);
251 newact.sa_flags = 0;
252 sigaction (SIGCONT, &newact, NULL);
254 initialized = true;
257 suspended = 0;
259 if (my_usleep (requested_delay) == -1)
261 if (suspended)
263 /* Calculate time remaining. */
264 /* FIXME: the code in sleep doesn't use this, so there's no
265 rush to implement it. */
267 errno = EINTR;
269 return -1;
272 /* FIXME: Restore sig handler? */
274 return 0;
276 #endif