From a50636ffed0c19358f6684e5f3a81fa88a4c7d4e Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 31 Aug 2006 07:00:50 +0000 Subject: [PATCH] Work around a bug in both the Linux and SunOS 64-bit kernels: nanosleep mishandles sleeps for longer than 2**31 seconds. Problem reported by Frank v Waveren in . * lib/nanosleep.c (BILLION): New constant. (getnow) [HAVE_BUG_BIG_NANOSLEEP]: New functions. (rpl_nanosleep) [HAVE_BUG_BIG_NANOSLEEP]: Completely new implementation. * m4/nanosleep.m4 (gl_FUNC_NANOSLEEP): Require gl_CLOCK_TIME. * modules/nanosleep (Depends-on): Add gettime. --- ChangeLog | 4 +++ lib/ChangeLog | 10 ++++++ lib/nanosleep.c | 77 +++++++++++++++++++++++++++++++++++++----- m4/ChangeLog | 10 ++++++ m4/nanosleep.m4 | 90 +++++++++++++++++++++++++++++++++++-------------- modules/gettime | 1 + 6 files changed, 158 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5d2991e126..895d329407 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2006-08-30 Paul Eggert + + * modules/nanosleep (Depends-on): Add gettime. + 2006-08-30 Paul Eggert and Simon Josefsson and Oskar Liljeblad diff --git a/lib/ChangeLog b/lib/ChangeLog index 073b4e5ce7..ee0895f8b9 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,13 @@ +2006-08-30 Paul Eggert + + Work around a bug in both the Linux and SunOS 64-bit kernels: + nanosleep mishandles sleeps for longer than 2**31 seconds. + Problem reported by Frank v Waveren in + . + * nanosleep.c (BILLION): New constant. + (getnow) [HAVE_BUG_BIG_NANOSLEEP]: New functions. + (rpl_nanosleep) [HAVE_BUG_BIG_NANOSLEEP]: Completely new implementation. + 2006-08-30 Jim Meyering * isapipe.c (isapipe): Rename local s/fd/fd_pair/ to avoid shadowing diff --git a/lib/nanosleep.c b/lib/nanosleep.c index 7ffe05d2eb..62b9f851aa 100644 --- a/lib/nanosleep.c +++ b/lib/nanosleep.c @@ -52,16 +52,74 @@ #include "timespec.h" +enum { BILLION = 1000 * 1000 * 1000 }; + +#if HAVE_BUG_BIG_NANOSLEEP + +void +getnow (struct timespec *t) +{ +# if defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME + if (clock_gettime (CLOCK_MONOTONIC, t) == 0) + return; +# endif + gettime (t); +} + +int +rpl_nanosleep (const struct timespec *requested_delay, + struct timespec *remaining_delay) +{ + /* nanosleep mishandles large sleeps due to internal overflow + problems, so check that the proper amount of time has actually + elapsed. */ + + struct timespec delay = *requested_delay; + struct timespec t0; + getnow (&t0); + + for (;;) + { + int r = nanosleep (&delay, remaining_delay); + if (r == 0) + { + time_t secs_sofar; + struct timespec now; + getnow (&now); + + secs_sofar = now.tv_sec - t0.tv_sec; + if (requested_delay->tv_sec < secs_sofar) + return 0; + delay.tv_sec = requested_delay->tv_sec - secs_sofar; + delay.tv_nsec = requested_delay->tv_nsec - (now.tv_nsec - t0.tv_nsec); + if (delay.tv_nsec < 0) + { + if (delay.tv_sec == 0) + return 0; + delay.tv_nsec += BILLION; + delay.tv_sec--; + } + else if (BILLION <= delay.tv_nsec) + { + delay.tv_nsec -= BILLION; + delay.tv_sec++; + } + } + } +} + +#else + /* Some systems (MSDOS) don't have SIGCONT. Using SIGTERM here turns the signal-handling code below into a no-op on such systems. */ -#ifndef SIGCONT -# define SIGCONT SIGTERM -#endif +# ifndef SIGCONT +# define SIGCONT SIGTERM +# endif -#if ! HAVE_SIGINTERRUPT -# define siginterrupt(sig, flag) /* empty */ -#endif +# if ! HAVE_SIGINTERRUPT +# define siginterrupt(sig, flag) /* empty */ +# endif static sig_atomic_t volatile suspended; @@ -107,7 +165,7 @@ rpl_nanosleep (const struct timespec *requested_delay, /* set up sig handler */ if (! initialized) { -#ifdef SA_NOCLDSTOP +# ifdef SA_NOCLDSTOP struct sigaction oldact, newact; newact.sa_handler = sighandler; sigemptyset (&newact.sa_mask); @@ -116,13 +174,13 @@ rpl_nanosleep (const struct timespec *requested_delay, sigaction (SIGCONT, NULL, &oldact); if (oldact.sa_handler != SIG_IGN) sigaction (SIGCONT, &newact, NULL); -#else +# else if (signal (SIGCONT, SIG_IGN) != SIG_IGN) { signal (SIGCONT, sighandler); siginterrupt (SIGCONT, 1); } -#endif +# endif initialized = true; } @@ -143,3 +201,4 @@ rpl_nanosleep (const struct timespec *requested_delay, return suspended; } +#endif diff --git a/m4/ChangeLog b/m4/ChangeLog index 3a265cd102..8f92897ab8 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,13 @@ +2006-08-30 Paul Eggert + + Work around a bug in both the Linux and SunOS 64-bit kernels: + nanosleep mishandles sleeps for longer than 2**31 seconds. + Problem reported by Frank v Waveren in + . + * nanosleep.m4 (gl_FUNC_NANOSLEEP): Require gl_CLOCK_TIME. + Check for nanosleep bug. + (LIB_NANOSLEEP): Append clock_gettime library if needed. + 2006-08-29 Paul Eggert * isapipe.m4: New file. diff --git a/m4/nanosleep.m4 b/m4/nanosleep.m4 index 88e630e897..9741b15285 100644 --- a/m4/nanosleep.m4 +++ b/m4/nanosleep.m4 @@ -1,4 +1,4 @@ -#serial 18 +#serial 19 dnl From Jim Meyering. dnl Check for the nanosleep function. @@ -18,6 +18,7 @@ AC_DEFUN([gl_FUNC_NANOSLEEP], AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_REQUIRE([AC_HEADER_TIME]) + AC_REQUIRE([gl_CLOCK_TIME]) AC_CHECK_HEADERS_ONCE(sys/time.h) nanosleep_save_libs=$LIBS @@ -27,42 +28,81 @@ AC_DEFUN([gl_FUNC_NANOSLEEP], AC_SEARCH_LIBS([nanosleep], [rt posix4], [test "$ac_cv_search_nanosleep" = "none required" || LIB_NANOSLEEP=$ac_cv_search_nanosleep]) - AC_SUBST([LIB_NANOSLEEP]) - AC_CACHE_CHECK([for nanosleep], + AC_CACHE_CHECK([for working nanosleep], [gl_cv_func_nanosleep], [ - AC_LINK_IFELSE([AC_LANG_SOURCE([[ -# if TIME_WITH_SYS_TIME -# include -# include -# else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -# endif + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + #if TIME_WITH_SYS_TIME + #include + #include + #else + #if HAVE_SYS_TIME_H + #include + #else + #include + #endif + #endif + #include + #include + #include + #include + #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + #define TYPE_MAXIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) -1 \ + : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))) + + static void + check_for_SIGALRM (int sig) + { + if (sig != SIGALRM) + _exit (1); + } - int - main () - { - struct timespec ts_sleep, ts_remaining; - ts_sleep.tv_sec = 0; - ts_sleep.tv_nsec = 1; - return nanosleep (&ts_sleep, &ts_remaining) < 0; - } - ]])], + int + main () + { + static struct timespec ts_sleep; + static struct timespec ts_remaining; + static struct sigaction act; + act.sa_handler = check_for_SIGALRM; + sigemptyset (&act.sa_mask); + sigaction (SIGALRM, &act, NULL); + ts_sleep.tv_sec = TYPE_MAXIMUM (time_t); + ts_sleep.tv_nsec = 999999999; + alarm (1); + if (nanosleep (&ts_sleep, &ts_remaining) == -1 && errno == EINTR + && TYPE_MAXIMUM (time_t) - 10 < ts_remaining.tv_sec) + return 0; + return 119; + }]])], [gl_cv_func_nanosleep=yes], - [gl_cv_func_nanosleep=no]) + [case $? in dnl ( + 119) gl_cv_func_nanosleep='no (mishandles large arguments)';; dnl ( + *) gl_cv_func_nanosleep=no;; + esac], + [gl_cv_func_nanosleep=cross-compiling]) ]) - if test $gl_cv_func_nanosleep = no; then + if test "$gl_cv_func_nanosleep" != yes; then + if test "$gl_cv_func_nanosleep" = 'no (mishandles large arguments)'; then + AC_DEFINE([HAVE_BUG_BIG_NANOSLEEP], 1, + [Define to 1 if nanosleep mishandle large arguments.]) + for ac_lib in $LIB_CLOCK_GETTIME; do + case " $LIB_NANOSLEEP " in + *" $ac_lib "*) ;; + *) LIB_NANOSLEEP="$LIB_NANOSLEEP $ac_lib";; + esac + done + fi AC_LIBOBJ(nanosleep) AC_DEFINE(nanosleep, rpl_nanosleep, [Define to rpl_nanosleep if the replacement function should be used.]) gl_PREREQ_NANOSLEEP fi + AC_SUBST([LIB_NANOSLEEP]) LIBS=$nanosleep_save_libs ]) diff --git a/modules/gettime b/modules/gettime index bdaec914a1..e6334efece 100644 --- a/modules/gettime +++ b/modules/gettime @@ -7,6 +7,7 @@ m4/clock_time.m4 m4/gettime.m4 Depends-on: +gettime gettimeofday timespec extensions -- 2.30.2