X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fnanosleep.c;h=17572dcef1b09764da0c5b37c43ff7d0b474ed2d;hb=c358102053be9ce7f33788c579f6e1e034f143c9;hp=58fc7881eceedd4be36c145d516827879ba58195;hpb=b2e2010c7c902235b5efb5bd3c6529f61b093aa4;p=gnulib.git diff --git a/lib/nanosleep.c b/lib/nanosleep.c index 58fc7881e..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 @@ -36,15 +37,15 @@ #include -#undef nanosleep enum { BILLION = 1000 * 1000 * 1000 }; #if HAVE_BUG_BIG_NANOSLEEP int -rpl_nanosleep (const struct timespec *requested_delay, - struct timespec *remaining_delay) +nanosleep (const struct timespec *requested_delay, + struct timespec *remaining_delay) +#undef nanosleep { /* nanosleep mishandles large sleeps due to internal overflow problems. The worst known case of this is cygwin 1.5.x, which @@ -83,7 +84,102 @@ rpl_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 @@ -128,8 +224,8 @@ 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;