maint: update copyright
[gnulib.git] / lib / nanosleep.c
index 62b9f85..d0b12e7 100644 (file)
@@ -1,12 +1,11 @@
 /* Provide a replacement for the POSIX nanosleep function.
 
-   Copyright (C) 1999, 2000, 2002, 2004, 2005, 2006 Free Software
-   Foundation, Inc.
+   Copyright (C) 1999-2000, 2002, 2004-2014 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-/* written by Jim Meyering */
+/* written by Jim Meyering
+   and Bruno Haible for the native Windows part */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
+
+#include <time.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)  */
-#undef nanosleep
+#include "intprops.h"
+#include "sig-handler.h"
+#include "verify.h"
 
 #include <stdbool.h>
 #include <stdio.h>
-#if HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
 #include <sys/types.h>
+#include <sys/select.h>
 #include <signal.h>
 
-#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 <sys/time.h>
 #include <errno.h>
 
 #include <unistd.h>
 
-#include "timespec.h"
 
 enum { BILLION = 1000 * 1000 * 1000 };
 
 #if HAVE_BUG_BIG_NANOSLEEP
 
-void
-getnow (struct timespec *t)
+int
+nanosleep (const struct timespec *requested_delay,
+           struct timespec *remaining_delay)
+# undef nanosleep
 {
-# if defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME
-  if (clock_gettime (CLOCK_MONOTONIC, t) == 0)
-    return;
-# endif
-  gettime (t);
+  /* nanosleep mishandles large sleeps due to internal overflow problems.
+     The worst known case of this is Linux 2.6.9 with glibc 2.3.4, which
+     can't sleep more than 24.85 days (2^31 milliseconds).  Similarly,
+     cygwin 1.5.x, which can't sleep more than 49.7 days (2^32 milliseconds).
+     Solve this by breaking the sleep up into smaller chunks.  */
+
+  if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  {
+    /* Verify that time_t is large enough.  */
+    verify (TYPE_MAXIMUM (time_t) / 24 / 24 / 60 / 60);
+    const time_t limit = 24 * 24 * 60 * 60;
+    time_t seconds = requested_delay->tv_sec;
+    struct timespec intermediate;
+    intermediate.tv_nsec = requested_delay->tv_nsec;
+
+    while (limit < seconds)
+      {
+        int result;
+        intermediate.tv_sec = limit;
+        result = nanosleep (&intermediate, remaining_delay);
+        seconds -= limit;
+        if (result)
+          {
+            if (remaining_delay)
+              remaining_delay->tv_sec += seconds;
+            return result;
+          }
+        intermediate.tv_nsec = 0;
+      }
+    intermediate.tv_sec = seconds;
+    return nanosleep (&intermediate, remaining_delay);
+  }
 }
 
+#elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Native Windows platforms.  */
+
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+
+/* The Windows API function Sleep() has a resolution of about 15 ms and takes
+   at least 5 ms to execute.  We use this function for longer time periods.
+   Additionally, we use busy-looping over short time periods, to get a
+   resolution of about 0.01 ms.  In order to measure such short timespans,
+   we use the QueryPerformanceCounter() function.  */
+
 int
-rpl_nanosleep (const struct timespec *requested_delay,
-              struct timespec *remaining_delay)
+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.  */
+  static bool initialized;
+  /* Number of performance counter increments per nanosecond,
+     or zero if it could not be determined.  */
+  static double ticks_per_nanosecond;
 
-  struct timespec delay = *requested_delay;
-  struct timespec t0;
-  getnow (&t0);
+  if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* For requested delays of one second or more, 15ms resolution is
+     sufficient.  */
+  if (requested_delay->tv_sec == 0)
+    {
+      if (!initialized)
+        {
+          /* Initialize ticks_per_nanosecond.  */
+          LARGE_INTEGER ticks_per_second;
+
+          if (QueryPerformanceFrequency (&ticks_per_second))
+            ticks_per_nanosecond =
+              (double) ticks_per_second.QuadPart / 1000000000.0;
+
+          initialized = true;
+        }
+      if (ticks_per_nanosecond)
+        {
+          /* QueryPerformanceFrequency worked.  We can use
+             QueryPerformanceCounter.  Use a combination of Sleep and
+             busy-looping.  */
+          /* Number of milliseconds to pass to the Sleep function.
+             Since Sleep can take up to 8 ms less or 8 ms more than requested
+             (or maybe more if the system is loaded), we subtract 10 ms.  */
+          int sleep_millis = (int) requested_delay->tv_nsec / 1000000 - 10;
+          /* Determine how many ticks to delay.  */
+          LONGLONG wait_ticks = requested_delay->tv_nsec * ticks_per_nanosecond;
+          /* Start.  */
+          LARGE_INTEGER counter_before;
+          if (QueryPerformanceCounter (&counter_before))
+            {
+              /* Wait until the performance counter has reached this value.
+                 We don't need to worry about overflow, because the performance
+                 counter is reset at reboot, and with a frequency of 3.6E6
+                 ticks per second 63 bits suffice for over 80000 years.  */
+              LONGLONG wait_until = counter_before.QuadPart + wait_ticks;
+              /* Use Sleep for the longest part.  */
+              if (sleep_millis > 0)
+                Sleep (sleep_millis);
+              /* Busy-loop for the rest.  */
+              for (;;)
+                {
+                  LARGE_INTEGER counter_after;
+                  if (!QueryPerformanceCounter (&counter_after))
+                    /* QueryPerformanceCounter failed, but succeeded earlier.
+                       Should not happen.  */
+                    break;
+                  if (counter_after.QuadPart >= wait_until)
+                    /* The requested time has elapsed.  */
+                    break;
+                }
+              goto done;
+            }
+        }
+    }
+  /* Implementation for long delays and as fallback.  */
+  Sleep (requested_delay->tv_sec * 1000 + requested_delay->tv_nsec / 1000000);
 
-  for (;;)
+ done:
+  /* Sleep is not interruptible.  So there is no remaining delay.  */
+  if (remaining_delay != NULL)
     {
-      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++;
-           }
-       }
+      remaining_delay->tv_sec = 0;
+      remaining_delay->tv_nsec = 0;
     }
+  return 0;
 }
 
 #else
+/* Unix platforms lacking nanosleep. */
 
 /* Some systems (MSDOS) don't have SIGCONT.
    Using SIGTERM here turns the signal-handling code below
@@ -117,10 +190,6 @@ rpl_nanosleep (const struct timespec *requested_delay,
 #  define SIGCONT SIGTERM
 # endif
 
-# if ! HAVE_SIGINTERRUPT
-#  define siginterrupt(sig, flag) /* empty */
-# endif
-
 static sig_atomic_t volatile suspended;
 
 /* Handle SIGCONT. */
@@ -141,14 +210,13 @@ my_usleep (const struct timespec *ts_delay)
   tv_delay.tv_usec = (ts_delay->tv_nsec + 999) / 1000;
   if (tv_delay.tv_usec == 1000000)
     {
-      time_t t1 = tv_delay.tv_sec + 1;
-      if (t1 < tv_delay.tv_sec)
-       tv_delay.tv_usec = 1000000 - 1; /* close enough */
+      if (tv_delay.tv_sec == TYPE_MAXIMUM (time_t))
+        tv_delay.tv_usec = 1000000 - 1; /* close enough */
       else
-       {
-         tv_delay.tv_sec = t1;
-         tv_delay.tv_usec = 0;
-       }
+        {
+          tv_delay.tv_sec++;
+          tv_delay.tv_usec = 0;
+        }
     }
   select (0, NULL, NULL, NULL, &tv_delay);
 }
@@ -157,30 +225,32 @@ my_usleep (const struct timespec *ts_delay)
    *REMAINING_DELAY part isn't implemented yet.  */
 
 int
-rpl_nanosleep (const struct timespec *requested_delay,
-              struct timespec *remaining_delay)
+nanosleep (const struct timespec *requested_delay,
+           struct timespec *remaining_delay)
 {
   static bool initialized;
 
+  if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
   /* set up sig handler */
   if (! initialized)
     {
-# ifdef SA_NOCLDSTOP
-      struct sigaction oldact, newact;
-      newact.sa_handler = sighandler;
-      sigemptyset (&newact.sa_mask);
-      newact.sa_flags = 0;
+      struct sigaction oldact;
 
       sigaction (SIGCONT, NULL, &oldact);
-      if (oldact.sa_handler != SIG_IGN)
-       sigaction (SIGCONT, &newact, NULL);
-# else
-      if (signal (SIGCONT, SIG_IGN) != SIG_IGN)
-       {
-         signal (SIGCONT, sighandler);
-         siginterrupt (SIGCONT, 1);
-       }
-# endif
+      if (get_handler (&oldact) != SIG_IGN)
+        {
+          struct sigaction newact;
+
+          newact.sa_handler = sighandler;
+          sigemptyset (&newact.sa_mask);
+          newact.sa_flags = 0;
+          sigaction (SIGCONT, &newact, NULL);
+        }
       initialized = true;
     }
 
@@ -192,7 +262,7 @@ rpl_nanosleep (const struct timespec *requested_delay,
     {
       /* Calculate time remaining.  */
       /* FIXME: the code in sleep doesn't use this, so there's no
-        rush to implement it.  */
+         rush to implement it.  */
 
       errno = EINTR;
     }