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:
parent
345c4c6532
commit
cdbc2f9d27
@ -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
|
||||
|
@ -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
195
lib/nanosleep.c
Normal 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
|
@ -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
139
m4/nanosleep.m4
Normal 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
|
||||
])
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user