X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fxnanosleep.c;h=1c7de6241ca47baf8fd53e1c4e10f1cab03cc4cd;hb=b7285ef59198ab3a562df0c91c6b1c781620e45e;hp=ebbd7ee89a1f1d9bf79800f59a01fc028ef20030;hpb=3ac9552429c5a500717e1d3d129c32f7d0ea37a3;p=gnulib.git diff --git a/lib/xnanosleep.c b/lib/xnanosleep.c index ebbd7ee89..1c7de6241 100644 --- a/lib/xnanosleep.c +++ b/lib/xnanosleep.c @@ -3,10 +3,10 @@ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 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 @@ -14,8 +14,7 @@ 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 . */ /* Mostly written (for sleep.c) by Paul Eggert. Factored out (creating this file) by Jim Meyering. */ @@ -50,36 +49,49 @@ xnanosleep (double seconds) { enum { BILLION = 1000000000 }; - bool overflow = false; - double ns; + /* For overflow checking, use naive comparison if possible, widening + to long double if double is not wide enough. Otherwise, use <=, + not <, to avoid problems when TIME_T_MAX is less than SECONDS but + compares equal to SECONDS after loss of precision when coercing + from time_t to long double. This mishandles near-maximal values + in some rare (perhaps theoretical) cases but that is better than + undefined behavior. */ + bool overflow = ((time_t) ((double) TIME_T_MAX / 2) == TIME_T_MAX / 2 + ? TIME_T_MAX < seconds + : (time_t) ((long double) TIME_T_MAX / 2) == TIME_T_MAX / 2 + ? TIME_T_MAX < (long double) seconds + : TIME_T_MAX <= (long double) seconds); + struct timespec ts_sleep; assert (0 <= seconds); - /* Separate whole seconds from nanoseconds. - Be careful to detect any overflow. */ - ts_sleep.tv_sec = seconds; - ns = BILLION * (seconds - ts_sleep.tv_sec); - overflow |= ! (ts_sleep.tv_sec <= seconds && 0 <= ns && ns <= BILLION); - 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 (BILLION <= ts_sleep.tv_nsec) + /* Separate whole seconds from nanoseconds. */ + if (! overflow) { - 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 -= BILLION; + time_t floor_seconds = seconds; + double ns = BILLION * (seconds - floor_seconds); + ts_sleep.tv_sec = floor_seconds; + + /* 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 = ns; + ts_sleep.tv_nsec += (ts_sleep.tv_nsec < ns); + + /* Normalize the interval length. nanosleep requires this. */ + if (BILLION <= ts_sleep.tv_nsec) + { + if (ts_sleep.tv_sec == TIME_T_MAX) + overflow = true; + else + { + ts_sleep.tv_sec++; + ts_sleep.tv_nsec -= BILLION; + } + } } for (;;)