/src/wget2/lib/nanosleep.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Provide a replacement for the POSIX nanosleep function. |
2 | | |
3 | | Copyright (C) 1999-2000, 2002, 2004-2025 Free Software Foundation, Inc. |
4 | | |
5 | | This file is free software: you can redistribute it and/or modify |
6 | | it under the terms of the GNU Lesser General Public License as |
7 | | published by the Free Software Foundation; either version 2.1 of the |
8 | | License, or (at your option) any later version. |
9 | | |
10 | | This file 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 Lesser General Public License for more details. |
14 | | |
15 | | You should have received a copy of the GNU Lesser General Public License |
16 | | along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
17 | | |
18 | | /* written by Jim Meyering |
19 | | and Bruno Haible for the native Windows part */ |
20 | | |
21 | | #include <config.h> |
22 | | |
23 | | #include <time.h> |
24 | | |
25 | | #include "intprops.h" |
26 | | |
27 | | #include <stdio.h> |
28 | | #include <sys/types.h> |
29 | | #include <sys/select.h> |
30 | | #include <signal.h> |
31 | | |
32 | | #include <errno.h> |
33 | | |
34 | | #include <unistd.h> |
35 | | |
36 | | |
37 | | enum { BILLION = 1000 * 1000 * 1000 }; |
38 | | |
39 | | #if HAVE_BUG_BIG_NANOSLEEP |
40 | | |
41 | | int |
42 | | nanosleep (const struct timespec *requested_delay, |
43 | | struct timespec *remaining_delay) |
44 | | # undef nanosleep |
45 | 0 | { |
46 | | /* nanosleep mishandles large sleeps due to internal overflow problems. |
47 | | The worst known case of this is Linux 2.6.9 with glibc 2.3.4, which |
48 | | can't sleep more than 24.85 days (2^31 milliseconds). Similarly, |
49 | | cygwin 1.5.x, which can't sleep more than 49.7 days (2^32 milliseconds). |
50 | | Solve this by breaking the sleep up into smaller chunks. */ |
51 | |
|
52 | 0 | if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec) |
53 | 0 | { |
54 | 0 | errno = EINVAL; |
55 | 0 | return -1; |
56 | 0 | } |
57 | | |
58 | 0 | { |
59 | | /* Verify that time_t is large enough. */ |
60 | 0 | static_assert (TYPE_MAXIMUM (time_t) / 24 / 24 / 60 / 60); |
61 | 0 | const time_t limit = 24 * 24 * 60 * 60; |
62 | 0 | time_t seconds = requested_delay->tv_sec; |
63 | 0 | struct timespec intermediate = *requested_delay; |
64 | |
|
65 | 0 | while (limit < seconds) |
66 | 0 | { |
67 | 0 | int result; |
68 | 0 | intermediate.tv_sec = limit; |
69 | 0 | result = nanosleep (&intermediate, remaining_delay); |
70 | 0 | seconds -= limit; |
71 | 0 | if (result) |
72 | 0 | { |
73 | 0 | if (remaining_delay) |
74 | 0 | remaining_delay->tv_sec += seconds; |
75 | 0 | return result; |
76 | 0 | } |
77 | 0 | intermediate.tv_nsec = 0; |
78 | 0 | } |
79 | 0 | intermediate.tv_sec = seconds; |
80 | 0 | return nanosleep (&intermediate, remaining_delay); |
81 | 0 | } |
82 | 0 | } |
83 | | |
84 | | #elif defined _WIN32 && ! defined __CYGWIN__ |
85 | | /* Native Windows platforms. */ |
86 | | |
87 | | # define WIN32_LEAN_AND_MEAN |
88 | | # include <windows.h> |
89 | | |
90 | | /* The Windows API function Sleep() has a resolution of about 15 ms and takes |
91 | | at least 5 ms to execute. We use this function for longer time periods. |
92 | | Additionally, we use busy-looping over short time periods, to get a |
93 | | resolution of about 0.01 ms. In order to measure such short timespans, |
94 | | we use the QueryPerformanceCounter() function. */ |
95 | | |
96 | | int |
97 | | nanosleep (const struct timespec *requested_delay, |
98 | | struct timespec *remaining_delay) |
99 | | { |
100 | | static bool initialized; |
101 | | /* Number of performance counter increments per nanosecond, |
102 | | or zero if it could not be determined. */ |
103 | | static double ticks_per_nanosecond; |
104 | | |
105 | | if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec) |
106 | | { |
107 | | errno = EINVAL; |
108 | | return -1; |
109 | | } |
110 | | |
111 | | /* For requested delays of one second or more, 15ms resolution is |
112 | | sufficient. */ |
113 | | if (requested_delay->tv_sec == 0) |
114 | | { |
115 | | if (!initialized) |
116 | | { |
117 | | /* Initialize ticks_per_nanosecond. */ |
118 | | LARGE_INTEGER ticks_per_second; |
119 | | |
120 | | if (QueryPerformanceFrequency (&ticks_per_second)) |
121 | | ticks_per_nanosecond = |
122 | | (double) ticks_per_second.QuadPart / 1000000000.0; |
123 | | |
124 | | initialized = true; |
125 | | } |
126 | | if (ticks_per_nanosecond) |
127 | | { |
128 | | /* QueryPerformanceFrequency worked. We can use |
129 | | QueryPerformanceCounter. Use a combination of Sleep and |
130 | | busy-looping. */ |
131 | | /* Number of milliseconds to pass to the Sleep function. |
132 | | Since Sleep can take up to 8 ms less or 8 ms more than requested |
133 | | (or maybe more if the system is loaded), we subtract 10 ms. */ |
134 | | int sleep_millis = (int) requested_delay->tv_nsec / 1000000 - 10; |
135 | | /* Determine how many ticks to delay. */ |
136 | | LONGLONG wait_ticks = requested_delay->tv_nsec * ticks_per_nanosecond; |
137 | | /* Start. */ |
138 | | LARGE_INTEGER counter_before; |
139 | | if (QueryPerformanceCounter (&counter_before)) |
140 | | { |
141 | | /* Wait until the performance counter has reached this value. |
142 | | We don't need to worry about overflow, because the performance |
143 | | counter is reset at reboot, and with a frequency of 3.6E6 |
144 | | ticks per second 63 bits suffice for over 80000 years. */ |
145 | | LONGLONG wait_until = counter_before.QuadPart + wait_ticks; |
146 | | /* Use Sleep for the longest part. */ |
147 | | if (sleep_millis > 0) |
148 | | Sleep (sleep_millis); |
149 | | /* Busy-loop for the rest. */ |
150 | | for (;;) |
151 | | { |
152 | | LARGE_INTEGER counter_after; |
153 | | if (!QueryPerformanceCounter (&counter_after)) |
154 | | /* QueryPerformanceCounter failed, but succeeded earlier. |
155 | | Should not happen. */ |
156 | | break; |
157 | | if (counter_after.QuadPart >= wait_until) |
158 | | /* The requested time has elapsed. */ |
159 | | break; |
160 | | } |
161 | | goto done; |
162 | | } |
163 | | } |
164 | | } |
165 | | /* Implementation for long delays and as fallback. */ |
166 | | Sleep (requested_delay->tv_sec * 1000 + requested_delay->tv_nsec / 1000000); |
167 | | |
168 | | done: |
169 | | /* Sleep is not interruptible. So there is no remaining delay. */ |
170 | | if (remaining_delay != NULL) |
171 | | { |
172 | | remaining_delay->tv_sec = 0; |
173 | | remaining_delay->tv_nsec = 0; |
174 | | } |
175 | | return 0; |
176 | | } |
177 | | |
178 | | #else |
179 | | /* Other platforms lacking nanosleep. |
180 | | It's not clear whether these are still practical porting targets. |
181 | | For now, just fall back on pselect. */ |
182 | | |
183 | | /* Suspend execution for at least *REQUESTED_DELAY seconds. The |
184 | | *REMAINING_DELAY part isn't implemented yet. */ |
185 | | |
186 | | int |
187 | | nanosleep (const struct timespec *requested_delay, |
188 | | struct timespec *remaining_delay) |
189 | | { |
190 | | return pselect (0, NULL, NULL, NULL, requested_delay, NULL); |
191 | | } |
192 | | #endif |