diff options
| author | Lars Ingebrigtsen | 2022-03-04 16:27:10 +0100 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2022-03-04 16:27:10 +0100 |
| commit | cdbc2f9d274a23bcf6cb03046b1e5b4bdcedafb1 (patch) | |
| tree | aef3f6a300ddbfe0a55364f0dc310e27a391dbdc /lib | |
| parent | 345c4c6532d3784eed5acbaea8a78ce3aad071e4 (diff) | |
| download | emacs-cdbc2f9d274a23bcf6cb03046b1e5b4bdcedafb1.tar.gz emacs-cdbc2f9d274a23bcf6cb03046b1e5b4bdcedafb1.zip | |
Add some sleeps to gnutls_try_handshake
* admin/merge-gnulib (GNULIB_MODULES): Add the nanosleep module.
* m4/gnulib-comp.m4 (gl_EARLY):
* lib/gnulib.mk.in: Automatic update.
* m4/nanosleep.m4:
* lib/nanosleep.c: New module.
* nt/mingw-cfg.site (gl_cv_func_free_preserves_errno):
* nt/gnulib-cfg.mk (OMIT_GNULIB_MODULE_nanosleep): Omit nanosleep,
since mingw has it.
* src/gnutls.c (gnutls_try_handshake): Add some sleeping to the
busy-wait loop so that we don't use 100% CPU here (bug#32452).
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/gnulib.mk.in | 13 | ||||
| -rw-r--r-- | lib/nanosleep.c | 195 |
2 files changed, 208 insertions, 0 deletions
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 3a9f5b9818e..3deeca98bef 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in | |||
| @@ -129,6 +129,7 @@ | |||
| 129 | # minmax \ | 129 | # minmax \ |
| 130 | # mkostemp \ | 130 | # mkostemp \ |
| 131 | # mktime \ | 131 | # mktime \ |
| 132 | # nanosleep \ | ||
| 132 | # nproc \ | 133 | # nproc \ |
| 133 | # nstrftime \ | 134 | # nstrftime \ |
| 134 | # pathmax \ | 135 | # pathmax \ |
| @@ -207,6 +208,7 @@ CPP = @CPP@ | |||
| 207 | CPPFLAGS = @CPPFLAGS@ | 208 | CPPFLAGS = @CPPFLAGS@ |
| 208 | CRYPTOLIB = @CRYPTOLIB@ | 209 | CRYPTOLIB = @CRYPTOLIB@ |
| 209 | CXX = @CXX@ | 210 | CXX = @CXX@ |
| 211 | CXXCPP = @CXXCPP@ | ||
| 210 | CXXFLAGS = @CXXFLAGS@ | 212 | CXXFLAGS = @CXXFLAGS@ |
| 211 | CYGWIN_OBJ = @CYGWIN_OBJ@ | 213 | CYGWIN_OBJ = @CYGWIN_OBJ@ |
| 212 | C_SWITCH_MACHINE = @C_SWITCH_MACHINE@ | 214 | C_SWITCH_MACHINE = @C_SWITCH_MACHINE@ |
| @@ -283,6 +285,7 @@ GL_COND_OBJ_MEMPCPY_CONDITION = @GL_COND_OBJ_MEMPCPY_CONDITION@ | |||
| 283 | GL_COND_OBJ_MEMRCHR_CONDITION = @GL_COND_OBJ_MEMRCHR_CONDITION@ | 285 | GL_COND_OBJ_MEMRCHR_CONDITION = @GL_COND_OBJ_MEMRCHR_CONDITION@ |
| 284 | GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION = @GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION@ | 286 | GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION = @GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION@ |
| 285 | GL_COND_OBJ_MKOSTEMP_CONDITION = @GL_COND_OBJ_MKOSTEMP_CONDITION@ | 287 | GL_COND_OBJ_MKOSTEMP_CONDITION = @GL_COND_OBJ_MKOSTEMP_CONDITION@ |
| 288 | GL_COND_OBJ_NANOSLEEP_CONDITION = @GL_COND_OBJ_NANOSLEEP_CONDITION@ | ||
| 286 | GL_COND_OBJ_OPEN_CONDITION = @GL_COND_OBJ_OPEN_CONDITION@ | 289 | GL_COND_OBJ_OPEN_CONDITION = @GL_COND_OBJ_OPEN_CONDITION@ |
| 287 | GL_COND_OBJ_PSELECT_CONDITION = @GL_COND_OBJ_PSELECT_CONDITION@ | 290 | GL_COND_OBJ_PSELECT_CONDITION = @GL_COND_OBJ_PSELECT_CONDITION@ |
| 288 | GL_COND_OBJ_PTHREAD_SIGMASK_CONDITION = @GL_COND_OBJ_PTHREAD_SIGMASK_CONDITION@ | 291 | GL_COND_OBJ_PTHREAD_SIGMASK_CONDITION = @GL_COND_OBJ_PTHREAD_SIGMASK_CONDITION@ |
| @@ -2497,6 +2500,16 @@ EXTRA_libgnu_a_SOURCES += mktime.c | |||
| 2497 | endif | 2500 | endif |
| 2498 | ## end gnulib module mktime-internal | 2501 | ## end gnulib module mktime-internal |
| 2499 | 2502 | ||
| 2503 | ## begin gnulib module nanosleep | ||
| 2504 | ifeq (,$(OMIT_GNULIB_MODULE_nanosleep)) | ||
| 2505 | |||
| 2506 | ifneq (,$(GL_COND_OBJ_NANOSLEEP_CONDITION)) | ||
| 2507 | libgnu_a_SOURCES += nanosleep.c | ||
| 2508 | endif | ||
| 2509 | |||
| 2510 | endif | ||
| 2511 | ## end gnulib module nanosleep | ||
| 2512 | |||
| 2500 | ## begin gnulib module nproc | 2513 | ## begin gnulib module nproc |
| 2501 | ifeq (,$(OMIT_GNULIB_MODULE_nproc)) | 2514 | ifeq (,$(OMIT_GNULIB_MODULE_nproc)) |
| 2502 | 2515 | ||
diff --git a/lib/nanosleep.c b/lib/nanosleep.c new file mode 100644 index 00000000000..446794edc0b --- /dev/null +++ b/lib/nanosleep.c | |||
| @@ -0,0 +1,195 @@ | |||
| 1 | /* Provide a replacement for the POSIX nanosleep function. | ||
| 2 | |||
| 3 | Copyright (C) 1999-2000, 2002, 2004-2022 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 | #include "verify.h" | ||
| 27 | |||
| 28 | #include <stdbool.h> | ||
| 29 | #include <stdio.h> | ||
| 30 | #include <sys/types.h> | ||
| 31 | #include <sys/select.h> | ||
| 32 | #include <signal.h> | ||
| 33 | |||
| 34 | #include <errno.h> | ||
| 35 | |||
| 36 | #include <unistd.h> | ||
| 37 | |||
| 38 | |||
| 39 | enum { BILLION = 1000 * 1000 * 1000 }; | ||
| 40 | |||
| 41 | #if HAVE_BUG_BIG_NANOSLEEP | ||
| 42 | |||
| 43 | int | ||
| 44 | nanosleep (const struct timespec *requested_delay, | ||
| 45 | struct timespec *remaining_delay) | ||
| 46 | # undef nanosleep | ||
| 47 | { | ||
| 48 | /* nanosleep mishandles large sleeps due to internal overflow problems. | ||
| 49 | The worst known case of this is Linux 2.6.9 with glibc 2.3.4, which | ||
| 50 | can't sleep more than 24.85 days (2^31 milliseconds). Similarly, | ||
| 51 | cygwin 1.5.x, which can't sleep more than 49.7 days (2^32 milliseconds). | ||
| 52 | Solve this by breaking the sleep up into smaller chunks. */ | ||
| 53 | |||
| 54 | if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec) | ||
| 55 | { | ||
| 56 | errno = EINVAL; | ||
| 57 | return -1; | ||
| 58 | } | ||
| 59 | |||
| 60 | { | ||
| 61 | /* Verify that time_t is large enough. */ | ||
| 62 | verify (TYPE_MAXIMUM (time_t) / 24 / 24 / 60 / 60); | ||
| 63 | const time_t limit = 24 * 24 * 60 * 60; | ||
| 64 | time_t seconds = requested_delay->tv_sec; | ||
| 65 | struct timespec intermediate; | ||
| 66 | intermediate.tv_nsec = requested_delay->tv_nsec; | ||
| 67 | |||
| 68 | while (limit < seconds) | ||
| 69 | { | ||
| 70 | int result; | ||
| 71 | intermediate.tv_sec = limit; | ||
| 72 | result = nanosleep (&intermediate, remaining_delay); | ||
| 73 | seconds -= limit; | ||
| 74 | if (result) | ||
| 75 | { | ||
| 76 | if (remaining_delay) | ||
| 77 | remaining_delay->tv_sec += seconds; | ||
| 78 | return result; | ||
| 79 | } | ||
| 80 | intermediate.tv_nsec = 0; | ||
| 81 | } | ||
| 82 | intermediate.tv_sec = seconds; | ||
| 83 | return nanosleep (&intermediate, remaining_delay); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | #elif defined _WIN32 && ! defined __CYGWIN__ | ||
| 88 | /* Native Windows platforms. */ | ||
| 89 | |||
| 90 | # define WIN32_LEAN_AND_MEAN | ||
| 91 | # include <windows.h> | ||
| 92 | |||
| 93 | /* The Windows API function Sleep() has a resolution of about 15 ms and takes | ||
| 94 | at least 5 ms to execute. We use this function for longer time periods. | ||
| 95 | Additionally, we use busy-looping over short time periods, to get a | ||
| 96 | resolution of about 0.01 ms. In order to measure such short timespans, | ||
| 97 | we use the QueryPerformanceCounter() function. */ | ||
| 98 | |||
| 99 | int | ||
| 100 | nanosleep (const struct timespec *requested_delay, | ||
| 101 | struct timespec *remaining_delay) | ||
| 102 | { | ||
| 103 | static bool initialized; | ||
| 104 | /* Number of performance counter increments per nanosecond, | ||
| 105 | or zero if it could not be determined. */ | ||
| 106 | static double ticks_per_nanosecond; | ||
| 107 | |||
| 108 | if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec) | ||
| 109 | { | ||
| 110 | errno = EINVAL; | ||
| 111 | return -1; | ||
| 112 | } | ||
| 113 | |||
| 114 | /* For requested delays of one second or more, 15ms resolution is | ||
| 115 | sufficient. */ | ||
| 116 | if (requested_delay->tv_sec == 0) | ||
| 117 | { | ||
| 118 | if (!initialized) | ||
| 119 | { | ||
| 120 | /* Initialize ticks_per_nanosecond. */ | ||
| 121 | LARGE_INTEGER ticks_per_second; | ||
| 122 | |||
| 123 | if (QueryPerformanceFrequency (&ticks_per_second)) | ||
| 124 | ticks_per_nanosecond = | ||
| 125 | (double) ticks_per_second.QuadPart / 1000000000.0; | ||
| 126 | |||
| 127 | initialized = true; | ||
| 128 | } | ||
| 129 | if (ticks_per_nanosecond) | ||
| 130 | { | ||
| 131 | /* QueryPerformanceFrequency worked. We can use | ||
| 132 | QueryPerformanceCounter. Use a combination of Sleep and | ||
| 133 | busy-looping. */ | ||
| 134 | /* Number of milliseconds to pass to the Sleep function. | ||
| 135 | Since Sleep can take up to 8 ms less or 8 ms more than requested | ||
| 136 | (or maybe more if the system is loaded), we subtract 10 ms. */ | ||
| 137 | int sleep_millis = (int) requested_delay->tv_nsec / 1000000 - 10; | ||
| 138 | /* Determine how many ticks to delay. */ | ||
| 139 | LONGLONG wait_ticks = requested_delay->tv_nsec * ticks_per_nanosecond; | ||
| 140 | /* Start. */ | ||
| 141 | LARGE_INTEGER counter_before; | ||
| 142 | if (QueryPerformanceCounter (&counter_before)) | ||
| 143 | { | ||
| 144 | /* Wait until the performance counter has reached this value. | ||
| 145 | We don't need to worry about overflow, because the performance | ||
| 146 | counter is reset at reboot, and with a frequency of 3.6E6 | ||
| 147 | ticks per second 63 bits suffice for over 80000 years. */ | ||
| 148 | LONGLONG wait_until = counter_before.QuadPart + wait_ticks; | ||
| 149 | /* Use Sleep for the longest part. */ | ||
| 150 | if (sleep_millis > 0) | ||
| 151 | Sleep (sleep_millis); | ||
| 152 | /* Busy-loop for the rest. */ | ||
| 153 | for (;;) | ||
| 154 | { | ||
| 155 | LARGE_INTEGER counter_after; | ||
| 156 | if (!QueryPerformanceCounter (&counter_after)) | ||
| 157 | /* QueryPerformanceCounter failed, but succeeded earlier. | ||
| 158 | Should not happen. */ | ||
| 159 | break; | ||
| 160 | if (counter_after.QuadPart >= wait_until) | ||
| 161 | /* The requested time has elapsed. */ | ||
| 162 | break; | ||
| 163 | } | ||
| 164 | goto done; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | } | ||
| 168 | /* Implementation for long delays and as fallback. */ | ||
| 169 | Sleep (requested_delay->tv_sec * 1000 + requested_delay->tv_nsec / 1000000); | ||
| 170 | |||
| 171 | done: | ||
| 172 | /* Sleep is not interruptible. So there is no remaining delay. */ | ||
| 173 | if (remaining_delay != NULL) | ||
| 174 | { | ||
| 175 | remaining_delay->tv_sec = 0; | ||
| 176 | remaining_delay->tv_nsec = 0; | ||
| 177 | } | ||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | #else | ||
| 182 | /* Other platforms lacking nanosleep. | ||
| 183 | It's not clear whether these are still practical porting targets. | ||
| 184 | For now, just fall back on pselect. */ | ||
| 185 | |||
| 186 | /* Suspend execution for at least *REQUESTED_DELAY seconds. The | ||
| 187 | *REMAINING_DELAY part isn't implemented yet. */ | ||
| 188 | |||
| 189 | int | ||
| 190 | nanosleep (const struct timespec *requested_delay, | ||
| 191 | struct timespec *remaining_delay) | ||
| 192 | { | ||
| 193 | return pselect (0, NULL, NULL, NULL, requested_delay, NULL); | ||
| 194 | } | ||
| 195 | #endif | ||