X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fxnanosleep.c;h=442ddf5c20a7121eb5c1f09b4f9aa99665541820;hb=a6b16b69fe1cad695b270dd5bf3deb2850fc4dd1;hp=6ca43e5603835290d4a0ccb0237d352b0ce1fca9;hpb=cc5b515f78b9b6a18defb5e632d14af5a4dc2ab6;p=gnulib.git diff --git a/lib/xnanosleep.c b/lib/xnanosleep.c index 6ca43e560..442ddf5c2 100644 --- a/lib/xnanosleep.c +++ b/lib/xnanosleep.c @@ -1,10 +1,11 @@ /* xnanosleep.c -- a more convenient interface to nanosleep - Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify + Copyright (C) 2002-2007, 2009-2011 Free Software Foundation, Inc. + + 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 @@ -12,77 +13,20 @@ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ /* Mostly written (for sleep.c) by Paul Eggert. Factored out (creating this file) by Jim Meyering. */ -#if HAVE_CONFIG_H -# include -#endif +#include #include "xnanosleep.h" -#include -#include -#include -#include +#include + #include -#include #include -/* The extra casts work around common compiler bugs. */ -#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) -/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. - It is necessary at least when t == time_t. */ -#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ - ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) -#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) - -#ifndef TIME_T_MAX -# define TIME_T_MAX TYPE_MAXIMUM (time_t) -#endif - -#include "timespec.h" -#include "xalloc.h" - -/* Subtract the `struct timespec' values X and Y by computing X - Y. - If the difference is negative or zero, return false. - Otherwise, return true and store the difference in DIFF. - X and Y must have valid ts_nsec values, in the range 0 to 999999999. - If the difference would overflow, store the maximum possible difference. */ - -static bool -timespec_subtract (struct timespec *diff, - struct timespec const *x, struct timespec const *y) -{ - time_t sec = x->tv_sec - y->tv_sec; - long int nsec = x->tv_nsec - y->tv_nsec; - - if (x->tv_sec < y->tv_sec) - return false; - - if (sec < 0) - { - /* The difference has overflowed. */ - sec = TIME_T_MAX; - nsec = 999999999; - } - else if (sec == 0 && nsec <= 0) - return false; - - if (nsec < 0) - { - sec--; - nsec += 1000000000; - } - - diff->tv_sec = sec; - diff->tv_nsec = nsec; - return true; -} - /* Sleep until the time (call it WAKE_UP_TIME) specified as SECONDS seconds after the time this function is called. SECONDS must be non-negative. If SECONDS is so large that @@ -93,79 +37,21 @@ timespec_subtract (struct timespec *diff, int xnanosleep (double seconds) { - bool overflow; - double ns; - struct timespec ts_start; - struct timespec ts_sleep; - struct timespec ts_stop; - - assert (0 <= seconds); + struct timespec ts_sleep = dtotimespec (seconds); - if (gettime (&ts_start) != 0) - return -1; - - /* Separate whole seconds from nanoseconds. - Be careful to detect any overflow. */ - ts_sleep.tv_sec = seconds; - ns = 1e9 * (seconds - ts_sleep.tv_sec); - overflow = ! (ts_sleep.tv_sec <= seconds && 0 <= ns && ns <= 1e9); - ts_sleep.tv_nsec = ns; - - /* Round up to the next whole number, if necessary, so that we - always sleep for at least the requested amount of time. Assuming - the default rounding mode, we don't have to worry about the - rounding error when computing 'ns' above, since the error won't - cause 'ns' to drop below an integer boundary. */ - ts_sleep.tv_nsec += (ts_sleep.tv_nsec < ns); - - /* Normalize the interval length. nanosleep requires this. */ - if (1000000000 <= ts_sleep.tv_nsec) + for (;;) { - time_t t = ts_sleep.tv_sec + 1; - - /* Detect integer overflow. */ - overflow |= (t < ts_sleep.tv_sec); - - ts_sleep.tv_sec = t; - ts_sleep.tv_nsec -= 1000000000; - } - - /* Compute the time until which we should sleep. */ - ts_stop.tv_sec = ts_start.tv_sec + ts_sleep.tv_sec; - ts_stop.tv_nsec = ts_start.tv_nsec + ts_sleep.tv_nsec; - if (1000000000 <= ts_stop.tv_nsec) - { - ++ts_stop.tv_sec; - ts_stop.tv_nsec -= 1000000000; - } - - /* Detect integer overflow. */ - overflow |= (ts_stop.tv_sec < ts_start.tv_sec - || (ts_stop.tv_sec == ts_start.tv_sec - && ts_stop.tv_nsec < ts_start.tv_nsec)); - - if (overflow) - { - /* Fix ts_sleep and ts_stop, which may be garbage due to overflow. */ - ts_sleep.tv_sec = ts_stop.tv_sec = TIME_T_MAX; - ts_sleep.tv_nsec = ts_stop.tv_nsec = 999999999; - } - - while (nanosleep (&ts_sleep, NULL) != 0) - { - if (errno != EINTR || gettime (&ts_start) != 0) - return -1; - - /* POSIX.1-2001 requires that when a process is suspended, then - resumed, nanosleep (A, B) returns -1, sets errno to EINTR, - and sets *B to the time remaining at the point of resumption. - However, some versions of the Linux kernel incorrectly return - the time remaining at the point of suspension. Work around - this bug by computing the remaining time here, rather than by - relying on nanosleep's computation. */ - - if (! timespec_subtract (&ts_sleep, &ts_stop, &ts_start)) - break; + /* Linux-2.6.8.1's nanosleep returns -1, but doesn't set errno + when resumed after being suspended. Earlier versions would + set errno to EINTR. nanosleep from linux-2.6.10, as well as + implementations by (all?) other vendors, doesn't return -1 + in that case; either it continues sleeping (if time remains) + or it returns zero (if the wake-up time has passed). */ + errno = 0; + if (nanosleep (&ts_sleep, NULL) == 0) + break; + if (errno != EINTR && errno != 0) + return -1; } return 0;