From c77f9c8110a2752a41e2befb227bdfb6b78632ee Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 4 Apr 2010 20:49:44 +0200 Subject: [PATCH] Implement nanosleep for native Windows. --- ChangeLog | 5 +++ lib/nanosleep.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index b6bec677e..b652cacfe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2010-04-04 Bruno Haible + Implement nanosleep for native Windows. + * lib/nanosleep.c (nanosleep): New implementation for native Windows. + +2010-04-04 Bruno Haible + math: Fix some C++ test errors on Solaris 8. * lib/math.in.h (truncf, trunc): Use simpler idiom. diff --git a/lib/nanosleep.c b/lib/nanosleep.c index be15cd08b..17572dcef 100644 --- a/lib/nanosleep.c +++ b/lib/nanosleep.c @@ -15,7 +15,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* written by Jim Meyering */ +/* written by Jim Meyering + and Bruno Haible for the Woe32 part */ #include @@ -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 + +/* 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 -- 2.11.0