changeset 7237:119870bc83d7

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>. * 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.
author Paul Eggert <eggert@cs.ucla.edu>
date Thu, 31 Aug 2006 07:00:50 +0000
parents c05b41ab8e3b
children e3f65c753bef
files ChangeLog lib/ChangeLog lib/nanosleep.c m4/ChangeLog m4/nanosleep.m4 modules/gettime
diffstat 6 files changed, 158 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+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>
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -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
--- 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 @@
   /* 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 @@
       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 @@
 
   return suspended;
 }
+#endif
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@ -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.
--- 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_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_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
 ])
 
--- a/modules/gettime
+++ b/modules/gettime
@@ -7,6 +7,7 @@
 m4/gettime.m4
 
 Depends-on:
+gettime
 gettimeofday
 timespec
 extensions