diff options
author | Jim Meyering <jim@meyering.net> | 2003-05-08 09:26:34 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2003-05-08 09:26:34 +0000 |
commit | de261015e86e6311e078330da6a6627ecec1d255 (patch) | |
tree | 580747d0a484fcf33b765cfab06b843aef5d2cc7 /lib | |
parent | f197628cb2e7192a8a8ba9b841fca068b50dd96d (diff) | |
download | coreutils-de261015e86e6311e078330da6a6627ecec1d255.tar.xz |
(timespec_subtract): Don't modify the 2nd arg.
Work even if X-Y overflows when subtracting. Make explicit the
assumption that tv_nsec must be in range.
(clock_get_realtime): Remove. All callers changed to invoke gettime,
for simplicity.
(xnanosleep): Check for gettime failure every time.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/xnanosleep.c | 63 |
1 files changed, 27 insertions, 36 deletions
diff --git a/lib/xnanosleep.c b/lib/xnanosleep.c index 097466e12..c4e9b469b 100644 --- a/lib/xnanosleep.c +++ b/lib/xnanosleep.c @@ -49,48 +49,40 @@ #include "xnanosleep.h" #include "xstrtod.h" -/* Subtract the `struct timespec' values X and Y, - storing the difference in DIFF. - Return 1 if the difference is positive, otherwise 0. - Derived from code in the GNU libc manual. */ +/* Subtract the `struct timespec' values X and Y by computing X - Y. + If the difference is negative or zero, return 0. + Otherwise, return 1 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 int timespec_subtract (struct timespec *diff, - const struct timespec *x, struct timespec *y) + struct timespec const *x, struct timespec const *y) { - /* Perform the carry for the later subtraction by updating Y. */ - if (x->tv_nsec < y->tv_nsec) + 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 0; + + if (sec < 0) { - int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1; - y->tv_nsec -= 1000000000 * nsec; - y->tv_sec += nsec; + /* The difference has overflowed. */ + sec = TIME_T_MAX; + nsec = 999999999; } + else if (sec == 0 && nsec <= 0) + return 0; - if (1000000000 < x->tv_nsec - y->tv_nsec) + if (nsec < 0) { - int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000; - y->tv_nsec += 1000000000 * nsec; - y->tv_sec -= nsec; + sec--; + nsec += 1000000000; } - /* Compute the time remaining to wait. - `tv_nsec' is certainly positive. */ - diff->tv_sec = x->tv_sec - y->tv_sec; - diff->tv_nsec = x->tv_nsec - y->tv_nsec; - - /* Return 1 if result is positive. */ - return y->tv_sec < x->tv_sec; -} - -struct timespec * -clock_get_realtime (struct timespec *ts) -{ - int fail = gettime (ts); - - if (fail) - return NULL; - - return ts; + diff->tv_sec = sec; + diff->tv_nsec = nsec; + return 1; } /* Sleep until the time (call it WAKE_UP_TIME) specified as @@ -111,7 +103,7 @@ xnanosleep (double seconds) assert (0 <= seconds); - if (clock_get_realtime (&ts_start) == NULL) + if (gettime (&ts_start) != 0) return -1; /* Separate whole seconds from nanoseconds. @@ -163,7 +155,7 @@ xnanosleep (double seconds) while (nanosleep (&ts_sleep, NULL) != 0) { - if (errno != EINTR) + if (errno != EINTR || gettime (&ts_start) != 0) return -1; /* POSIX.1-2001 requires that when a process is suspended, then @@ -174,8 +166,7 @@ xnanosleep (double seconds) this bug by computing the remaining time here, rather than by relying on nanosleep's computation. */ - if (! timespec_subtract (&ts_sleep, &ts_stop, - clock_get_realtime (&ts_start))) + if (! timespec_subtract (&ts_sleep, &ts_stop, &ts_start)) break; } |