bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: xnanosleep range with 64 bit time_t


From: Paul Eggert
Subject: Re: xnanosleep range with 64 bit time_t
Date: Thu, 31 Aug 2006 00:13:35 -0700
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.4 (gnu/linux)

I have installed the following patch to gnulib, which should work
around the bugs in SunOS and Linux nanosleep, though it won't work
around bugs in some of the changes being proposed for the Linux kernel
(changes that I hope are not accepted :-).

Obviously the kernel needs to get fixed too, as we can't have every
application writer writing dozens of lines of tricky code to work
around kernel bugs.  But one step at a time.

Thanks for reporting the problem.

2006-08-30  Paul Eggert  <address@hidden>

        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.

Index: lib/nanosleep.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/nanosleep.c,v
retrieving revision 1.18
diff -p -u -r1.18 nanosleep.c
--- lib/nanosleep.c     19 May 2006 17:49:21 -0000      1.18
+++ lib/nanosleep.c     31 Aug 2006 06:58:38 -0000
@@ -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
-
-#if ! HAVE_SIGINTERRUPT
-# define siginterrupt(sig, flag) /* empty */
-#endif
+# ifndef SIGCONT
+#  define SIGCONT SIGTERM
+# 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 *re
   /* 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 *re
       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 *re
 
   return suspended;
 }
+#endif
Index: m4/nanosleep.m4
===================================================================
RCS file: /cvsroot/gnulib/gnulib/m4/nanosleep.m4,v
retrieving revision 1.25
diff -p -u -r1.25 nanosleep.m4
--- m4/nanosleep.m4     21 Aug 2006 21:46:31 -0000      1.25
+++ m4/nanosleep.m4     31 Aug 2006 06:58:38 -0000
@@ -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
-
-    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;
-    }
-      ]])],
+   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 ()
+       {
+         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: modules/gettime
===================================================================
RCS file: /cvsroot/gnulib/gnulib/modules/gettime,v
retrieving revision 1.6
diff -p -u -r1.6 gettime
--- modules/gettime     2 Mar 2006 07:36:41 -0000       1.6
+++ modules/gettime     31 Aug 2006 06:58:38 -0000
@@ -7,6 +7,7 @@ m4/clock_time.m4
 m4/gettime.m4
 
 Depends-on:
+gettime
 gettimeofday
 timespec
 extensions




reply via email to

[Prev in Thread] Current Thread [Next in Thread]