1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-22 18:35:09 +00:00

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).
This commit is contained in:
Lars Ingebrigtsen 2022-03-04 16:27:10 +01:00
parent 345c4c6532
commit cdbc2f9d27
8 changed files with 363 additions and 1 deletions

View File

@ -40,7 +40,7 @@ GNULIB_MODULES='
getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog
ieee754-h ignore-value intprops largefile libgmp lstat
manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime
nproc nstrftime
nanosleep nproc nstrftime
pathmax pipe2 pselect pthread_sigmask
qcopy-acl readlink readlinkat regex
sig2str sigdescr_np socklen stat-time std-gnu11 stdalign stddef stdio

View File

@ -129,6 +129,7 @@
# minmax \
# mkostemp \
# mktime \
# nanosleep \
# nproc \
# nstrftime \
# pathmax \
@ -207,6 +208,7 @@ CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CRYPTOLIB = @CRYPTOLIB@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXFLAGS = @CXXFLAGS@
CYGWIN_OBJ = @CYGWIN_OBJ@
C_SWITCH_MACHINE = @C_SWITCH_MACHINE@
@ -283,6 +285,7 @@ GL_COND_OBJ_MEMPCPY_CONDITION = @GL_COND_OBJ_MEMPCPY_CONDITION@
GL_COND_OBJ_MEMRCHR_CONDITION = @GL_COND_OBJ_MEMRCHR_CONDITION@
GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION = @GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION@
GL_COND_OBJ_MKOSTEMP_CONDITION = @GL_COND_OBJ_MKOSTEMP_CONDITION@
GL_COND_OBJ_NANOSLEEP_CONDITION = @GL_COND_OBJ_NANOSLEEP_CONDITION@
GL_COND_OBJ_OPEN_CONDITION = @GL_COND_OBJ_OPEN_CONDITION@
GL_COND_OBJ_PSELECT_CONDITION = @GL_COND_OBJ_PSELECT_CONDITION@
GL_COND_OBJ_PTHREAD_SIGMASK_CONDITION = @GL_COND_OBJ_PTHREAD_SIGMASK_CONDITION@
@ -2497,6 +2500,16 @@ EXTRA_libgnu_a_SOURCES += mktime.c
endif
## end gnulib module mktime-internal
## begin gnulib module nanosleep
ifeq (,$(OMIT_GNULIB_MODULE_nanosleep))
ifneq (,$(GL_COND_OBJ_NANOSLEEP_CONDITION))
libgnu_a_SOURCES += nanosleep.c
endif
endif
## end gnulib module nanosleep
## begin gnulib module nproc
ifeq (,$(OMIT_GNULIB_MODULE_nproc))

195
lib/nanosleep.c Normal file
View File

@ -0,0 +1,195 @@
/* Provide a replacement for the POSIX nanosleep function.
Copyright (C) 1999-2000, 2002, 2004-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* written by Jim Meyering
and Bruno Haible for the native Windows part */
#include <config.h>
#include <time.h>
#include "intprops.h"
#include "verify.h"
#include <stdbool.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/select.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
enum { BILLION = 1000 * 1000 * 1000 };
#if HAVE_BUG_BIG_NANOSLEEP
int
nanosleep (const struct timespec *requested_delay,
struct timespec *remaining_delay)
# undef nanosleep
{
/* nanosleep mishandles large sleeps due to internal overflow problems.
The worst known case of this is Linux 2.6.9 with glibc 2.3.4, which
can't sleep more than 24.85 days (2^31 milliseconds). Similarly,
cygwin 1.5.x, which can't sleep more than 49.7 days (2^32 milliseconds).
Solve this by breaking the sleep up into smaller chunks. */
if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
{
errno = EINVAL;
return -1;
}
{
/* Verify that time_t is large enough. */
verify (TYPE_MAXIMUM (time_t) / 24 / 24 / 60 / 60);
const time_t limit = 24 * 24 * 60 * 60;
time_t seconds = requested_delay->tv_sec;
struct timespec intermediate;
intermediate.tv_nsec = requested_delay->tv_nsec;
while (limit < seconds)
{
int result;
intermediate.tv_sec = limit;
result = nanosleep (&intermediate, remaining_delay);
seconds -= limit;
if (result)
{
if (remaining_delay)
remaining_delay->tv_sec += seconds;
return result;
}
intermediate.tv_nsec = 0;
}
intermediate.tv_sec = seconds;
return nanosleep (&intermediate, remaining_delay);
}
}
#elif defined _WIN32 && ! defined __CYGWIN__
/* Native Windows platforms. */
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
/* The Windows API function Sleep() has a resolution of about 15 ms and takes
at least 5 ms to execute. We use this function for longer time periods.
Additionally, we use busy-looping over short time periods, to get a
resolution of about 0.01 ms. In order to measure such short timespans,
we use the QueryPerformanceCounter() function. */
int
nanosleep (const struct timespec *requested_delay,
struct timespec *remaining_delay)
{
static bool initialized;
/* Number of performance counter increments per nanosecond,
or zero if it could not be determined. */
static double ticks_per_nanosecond;
if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
{
errno = EINVAL;
return -1;
}
/* For requested delays of one second or more, 15ms resolution is
sufficient. */
if (requested_delay->tv_sec == 0)
{
if (!initialized)
{
/* Initialize ticks_per_nanosecond. */
LARGE_INTEGER ticks_per_second;
if (QueryPerformanceFrequency (&ticks_per_second))
ticks_per_nanosecond =
(double) ticks_per_second.QuadPart / 1000000000.0;
initialized = true;
}
if (ticks_per_nanosecond)
{
/* QueryPerformanceFrequency worked. We can use
QueryPerformanceCounter. Use a combination of Sleep and
busy-looping. */
/* Number of milliseconds to pass to the Sleep function.
Since Sleep can take up to 8 ms less or 8 ms more than requested
(or maybe more if the system is loaded), we subtract 10 ms. */
int sleep_millis = (int) requested_delay->tv_nsec / 1000000 - 10;
/* Determine how many ticks to delay. */
LONGLONG wait_ticks = requested_delay->tv_nsec * ticks_per_nanosecond;
/* Start. */
LARGE_INTEGER counter_before;
if (QueryPerformanceCounter (&counter_before))
{
/* Wait until the performance counter has reached this value.
We don't need to worry about overflow, because the performance
counter is reset at reboot, and with a frequency of 3.6E6
ticks per second 63 bits suffice for over 80000 years. */
LONGLONG wait_until = counter_before.QuadPart + wait_ticks;
/* Use Sleep for the longest part. */
if (sleep_millis > 0)
Sleep (sleep_millis);
/* Busy-loop for the rest. */
for (;;)
{
LARGE_INTEGER counter_after;
if (!QueryPerformanceCounter (&counter_after))
/* QueryPerformanceCounter failed, but succeeded earlier.
Should not happen. */
break;
if (counter_after.QuadPart >= wait_until)
/* The requested time has elapsed. */
break;
}
goto done;
}
}
}
/* Implementation for long delays and as fallback. */
Sleep (requested_delay->tv_sec * 1000 + requested_delay->tv_nsec / 1000000);
done:
/* Sleep is not interruptible. So there is no remaining delay. */
if (remaining_delay != NULL)
{
remaining_delay->tv_sec = 0;
remaining_delay->tv_nsec = 0;
}
return 0;
}
#else
/* Other platforms lacking nanosleep.
It's not clear whether these are still practical porting targets.
For now, just fall back on pselect. */
/* Suspend execution for at least *REQUESTED_DELAY seconds. The
*REMAINING_DELAY part isn't implemented yet. */
int
nanosleep (const struct timespec *requested_delay,
struct timespec *remaining_delay)
{
return pselect (0, NULL, NULL, NULL, requested_delay, NULL);
}
#endif

View File

@ -140,6 +140,7 @@ AC_DEFUN([gl_EARLY],
# Code from module mktime:
# Code from module mktime-internal:
# Code from module multiarch:
# Code from module nanosleep:
# Code from module nocrash:
# Code from module nproc:
# Code from module nstrftime:
@ -430,6 +431,10 @@ AC_DEFUN([gl_INIT],
fi
gl_TIME_MODULE_INDICATOR([mktime])
gl_MULTIARCH
gl_FUNC_NANOSLEEP
gl_CONDITIONAL([GL_COND_OBJ_NANOSLEEP],
[test $HAVE_NANOSLEEP = 0 || test $REPLACE_NANOSLEEP = 1])
gl_TIME_MODULE_INDICATOR([nanosleep])
gl_NPROC
gl_FUNC_GNU_STRFTIME
gl_PATHMAX
@ -1304,6 +1309,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/mkostemp.c
lib/mktime-internal.h
lib/mktime.c
lib/nanosleep.c
lib/nproc.c
lib/nproc.h
lib/nstrftime.c
@ -1456,6 +1462,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/mktime.m4
m4/mode_t.m4
m4/multiarch.m4
m4/nanosleep.m4
m4/nocrash.m4
m4/nproc.m4
m4/nstrftime.m4

139
m4/nanosleep.m4 Normal file
View File

@ -0,0 +1,139 @@
# serial 41
dnl From Jim Meyering.
dnl Check for the nanosleep function.
dnl If not found, use the supplied replacement.
dnl
# Copyright (C) 1999-2001, 2003-2022 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_FUNC_NANOSLEEP],
[
AC_REQUIRE([gl_TIME_H_DEFAULTS])
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
dnl Persuade glibc and Solaris <time.h> to declare nanosleep.
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
AC_CHECK_DECLS_ONCE([alarm])
nanosleep_save_libs=$LIBS
# Solaris 2.5.1 needs -lposix4 to get the nanosleep function.
# Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4.
LIB_NANOSLEEP=
AC_SUBST([LIB_NANOSLEEP])
AC_SEARCH_LIBS([nanosleep], [rt posix4],
[test "$ac_cv_search_nanosleep" = "none required" ||
LIB_NANOSLEEP=$ac_cv_search_nanosleep])
if test "x$ac_cv_search_nanosleep" != xno; then
dnl The system has a nanosleep function.
AC_REQUIRE([gl_MULTIARCH])
if test $APPLE_UNIVERSAL_BUILD = 1; then
# A universal build on Apple Mac OS X platforms.
# The test result would be 'no (mishandles large arguments)' in 64-bit
# mode but 'yes' in 32-bit mode. But we need a configuration result that
# is valid in both modes.
gl_cv_func_nanosleep='no (mishandles large arguments)'
fi
AC_CACHE_CHECK([for working nanosleep],
[gl_cv_func_nanosleep],
[
AC_RUN_IFELSE(
[AC_LANG_SOURCE([[
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
#define TYPE_MAXIMUM(t) \
((t) (! TYPE_SIGNED (t) \
? (t) -1 \
: ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
#if HAVE_DECL_ALARM
static void
check_for_SIGALRM (int sig)
{
if (sig != SIGALRM)
_exit (1);
}
#endif
int
main ()
{
static struct timespec ts_sleep;
static struct timespec ts_remaining;
/* Test for major problems first. */
if (! nanosleep)
return 2;
ts_sleep.tv_sec = 0;
ts_sleep.tv_nsec = 1;
#if HAVE_DECL_ALARM
{
static struct sigaction act;
act.sa_handler = check_for_SIGALRM;
sigemptyset (&act.sa_mask);
sigaction (SIGALRM, &act, NULL);
alarm (1);
if (nanosleep (&ts_sleep, NULL) != 0)
return 3;
/* Test for a minor problem: the handling of large arguments. */
ts_sleep.tv_sec = TYPE_MAXIMUM (time_t);
ts_sleep.tv_nsec = 999999999;
alarm (1);
if (nanosleep (&ts_sleep, &ts_remaining) != -1)
return 4;
if (errno != EINTR)
return 5;
if (ts_remaining.tv_sec <= TYPE_MAXIMUM (time_t) - 10)
return 6;
}
#else /* A simpler test for native Windows. */
if (nanosleep (&ts_sleep, &ts_remaining) < 0)
return 3;
#endif
return 0;
}]])],
[gl_cv_func_nanosleep=yes],
[case $? in dnl (
4|5|6) gl_cv_func_nanosleep='no (mishandles large arguments)';; dnl (
*) gl_cv_func_nanosleep=no;;
esac],
[case "$host_os" in dnl ((
linux*) # Guess it halfway works when the kernel is Linux.
gl_cv_func_nanosleep='guessing no (mishandles large arguments)' ;;
mingw*) # Guess no on native Windows.
gl_cv_func_nanosleep='guessing no' ;;
*) # If we don't know, obey --enable-cross-guesses.
gl_cv_func_nanosleep="$gl_cross_guess_normal" ;;
esac
])
])
case "$gl_cv_func_nanosleep" in
*yes)
REPLACE_NANOSLEEP=0
;;
*)
REPLACE_NANOSLEEP=1
case "$gl_cv_func_nanosleep" in
*"mishandles large arguments"*)
AC_DEFINE([HAVE_BUG_BIG_NANOSLEEP], [1],
[Define to 1 if nanosleep mishandles large arguments.])
;;
esac
;;
esac
else
HAVE_NANOSLEEP=0
fi
LIBS=$nanosleep_save_libs
])

View File

@ -74,3 +74,4 @@ OMIT_GNULIB_MODULE_futimens = true
OMIT_GNULIB_MODULE_utimensat = true
OMIT_GNULIB_MODULE_file-has-acl = true
OMIT_GNULIB_MODULE_nproc = true
OMIT_GNULIB_MODULE_nanosleep = true

View File

@ -167,3 +167,6 @@ ac_cv_func_strsignal=no
# implementation of 'free' doesn't touch errno, and it emits a
# compilation warning.
gl_cv_func_free_preserves_errno=yes
# Don't build the Gnulib nanosleep module: it requires W2K or later,
# and MinGW does have nanosleep.
gl_cv_func_nanosleep=yes

View File

@ -616,6 +616,9 @@ gnutls_try_handshake (struct Lisp_Process *proc)
gnutls_session_t state = proc->gnutls_state;
int ret;
bool non_blocking = proc->is_non_blocking_client;
/* Sleep for ten milliseconds when busy-looping in
gnutls_handshake. */
struct timespec delay = { 0, 1000 * 1000 * 10 };
if (proc->gnutls_complete_negotiation_p)
non_blocking = false;
@ -630,6 +633,7 @@ gnutls_try_handshake (struct Lisp_Process *proc)
maybe_quit ();
if (non_blocking && ret != GNUTLS_E_INTERRUPTED)
break;
nanosleep (&delay, NULL);
}
proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED;