]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
(timespec_subtract): Don't modify the 2nd arg.
authorJim Meyering <jim@meyering.net>
Thu, 8 May 2003 09:26:34 +0000 (09:26 +0000)
committerJim Meyering <jim@meyering.net>
Thu, 8 May 2003 09:26:34 +0000 (09:26 +0000)
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.

lib/xnanosleep.c

index 097466e127e0ec7dcbdd2d8a89f7170d2b668e23..c4e9b469b4083fd9ebca1e09c508d9bcb828b98a 100644 (file)
 #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;
     }