Work around a bug in both the Linux and SunOS 64-bit kernels:
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 31 Aug 2006 07:00:50 +0000 (07:00 +0000)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 31 Aug 2006 07:00:50 +0000 (07:00 +0000)
nanosleep mishandles sleeps for longer than 2**31 seconds.
Problem reported by Frank v Waveren in
<http://lists.gnu.org/archive/html/bug-coreutils/2006-08/msg00298.html>.
* 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
lib/ChangeLog
lib/nanosleep.c
m4/ChangeLog
m4/nanosleep.m4
modules/gettime

index 5d2991e..895d329 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,8 @@
 2006-08-30  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * modules/nanosleep (Depends-on): Add gettime.
+
+2006-08-30  Paul Eggert  <eggert@cs.ucla.edu>
        and Simon Josefsson  <jas@extundo.com>
        and Oskar Liljeblad  <oskar@osk.mine.nu>
 
index 073b4e5..ee0895f 100644 (file)
@@ -1,3 +1,13 @@
+2006-08-30  Paul Eggert  <eggert@cs.ucla.edu>
+
+       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
+       <http://lists.gnu.org/archive/html/bug-coreutils/2006-08/msg00298.html>.
+       * 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  <jim@meyering.net>
 
        * isapipe.c (isapipe): Rename local s/fd/fd_pair/ to avoid shadowing
index 7ffe05d..62b9f85 100644 (file)
 
 #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
index 3a265cd..8f92897 100644 (file)
@@ -1,3 +1,13 @@
+2006-08-30  Paul Eggert  <eggert@cs.ucla.edu>
+
+       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
+       <http://lists.gnu.org/archive/html/bug-coreutils/2006-08/msg00298.html>.
+       * 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  <eggert@cs.ucla.edu>
 
        * isapipe.m4: New file.
index 88e630e..9741b15 100644 (file)
@@ -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 <sys/time.h>
-#    include <time.h>
-#   else
-#    if HAVE_SYS_TIME_H
-#     include <sys/time.h>
-#    else
-#     include <time.h>
-#    endif
-#   endif
+   AC_RUN_IFELSE(
+     [AC_LANG_SOURCE([[
+       #if TIME_WITH_SYS_TIME
+        #include <sys/time.h>
+        #include <time.h>
+       #else
+        #if HAVE_SYS_TIME_H
+         #include <sys/time.h>
+        #else
+         #include <time.h>
+        #endif
+       #endif
+       #include <errno.h>
+       #include <limits.h>
+       #include <signal.h>
+       #include <unistd.h>
+       #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
 ])
 
index bdaec91..e6334ef 100644 (file)
@@ -7,6 +7,7 @@ m4/clock_time.m4
 m4/gettime.m4
 
 Depends-on:
+gettime
 gettimeofday
 timespec
 extensions