Implement nanosleep for native Windows.
authorBruno Haible <bruno@clisp.org>
Sun, 4 Apr 2010 18:49:44 +0000 (20:49 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 4 Apr 2010 18:49:44 +0000 (20:49 +0200)
ChangeLog
lib/nanosleep.c

index b6bec67..b652cac 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2010-04-04  Bruno Haible  <bruno@clisp.org>
 
+       Implement nanosleep for native Windows.
+       * lib/nanosleep.c (nanosleep): New implementation for native Windows.
+
+2010-04-04  Bruno Haible  <bruno@clisp.org>
+
        math: Fix some C++ test errors on Solaris 8.
        * lib/math.in.h (truncf, trunc): Use simpler idiom.
 
index be15cd0..17572dc 100644 (file)
@@ -15,7 +15,8 @@
    You should have received a copy of the GNU General Public License
    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 Woe32 part */
 
 #include <config.h>
 
@@ -83,7 +84,102 @@ nanosleep (const struct timespec *requested_delay,
   return nanosleep (&intermediate, remaining_delay);
 }
 
+#elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Windows platforms.  */
+
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+
+/* The Win32 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
+nanosleep (const struct timespec *requested_delay,
+           struct timespec *remaining_delay)
+{
+  static bool initialized;
+  /* Number of performance counter increments per nanosecond,
+     or zero if it could not be determined.  */
+  static double ticks_per_nanosecond;
+
+  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);
+
+ done:
+  /* Sleep is not interruptible.  So there is no remaining delay.  */
+  if (remaining_delay != NULL)
+    {
+      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