New modules 'unistr/u8-strmblen', 'unistr/u16-strmblen', 'unistr/u32-strmblen'.
[gnulib.git] / lib / nanosleep.c
index 7ffe05d..fe22a97 100644 (file)
@@ -19,9 +19,7 @@
 
 /* written by Jim Meyering */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
 
 /* Undefine nanosleep here so any prototype is not redefined to be a
    prototype for rpl_nanosleep. (they'd conflict e.g., on alpha-dec-osf3.2)  */
 
 #include <stdbool.h>
 #include <stdio.h>
+#include <sys/types.h>
 #if HAVE_SYS_SELECT_H
 # include <sys/select.h>
 #endif
-#include <sys/types.h>
 #include <signal.h>
 
 #if TIME_WITH_SYS_TIME
 
 #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 +163,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 +172,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 +199,4 @@ rpl_nanosleep (const struct timespec *requested_delay,
 
   return suspended;
 }
+#endif