Change one-line summary to reflect that shred does
[coreutils.git] / lib / xnanosleep.c
blob6ca43e5603835290d4a0ccb0237d352b0ce1fca9
1 /* xnanosleep.c -- a more convenient interface to nanosleep
2 Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Mostly written (for sleep.c) by Paul Eggert.
19 Factored out (creating this file) by Jim Meyering. */
21 #if HAVE_CONFIG_H
22 # include <config.h>
23 #endif
25 #include "xnanosleep.h"
27 #include <limits.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <time.h>
35 /* The extra casts work around common compiler bugs. */
36 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
37 /* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
38 It is necessary at least when t == time_t. */
39 #define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
40 ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
41 #define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
43 #ifndef TIME_T_MAX
44 # define TIME_T_MAX TYPE_MAXIMUM (time_t)
45 #endif
47 #include "timespec.h"
48 #include "xalloc.h"
50 /* Subtract the `struct timespec' values X and Y by computing X - Y.
51 If the difference is negative or zero, return false.
52 Otherwise, return true and store the difference in DIFF.
53 X and Y must have valid ts_nsec values, in the range 0 to 999999999.
54 If the difference would overflow, store the maximum possible difference. */
56 static bool
57 timespec_subtract (struct timespec *diff,
58 struct timespec const *x, struct timespec const *y)
60 time_t sec = x->tv_sec - y->tv_sec;
61 long int nsec = x->tv_nsec - y->tv_nsec;
63 if (x->tv_sec < y->tv_sec)
64 return false;
66 if (sec < 0)
68 /* The difference has overflowed. */
69 sec = TIME_T_MAX;
70 nsec = 999999999;
72 else if (sec == 0 && nsec <= 0)
73 return false;
75 if (nsec < 0)
77 sec--;
78 nsec += 1000000000;
81 diff->tv_sec = sec;
82 diff->tv_nsec = nsec;
83 return true;
86 /* Sleep until the time (call it WAKE_UP_TIME) specified as
87 SECONDS seconds after the time this function is called.
88 SECONDS must be non-negative. If SECONDS is so large that
89 it is not representable as a `struct timespec', then use
90 the maximum value for that interval. Return -1 on failure
91 (setting errno), 0 on success. */
93 int
94 xnanosleep (double seconds)
96 bool overflow;
97 double ns;
98 struct timespec ts_start;
99 struct timespec ts_sleep;
100 struct timespec ts_stop;
102 assert (0 <= seconds);
104 if (gettime (&ts_start) != 0)
105 return -1;
107 /* Separate whole seconds from nanoseconds.
108 Be careful to detect any overflow. */
109 ts_sleep.tv_sec = seconds;
110 ns = 1e9 * (seconds - ts_sleep.tv_sec);
111 overflow = ! (ts_sleep.tv_sec <= seconds && 0 <= ns && ns <= 1e9);
112 ts_sleep.tv_nsec = ns;
114 /* Round up to the next whole number, if necessary, so that we
115 always sleep for at least the requested amount of time. Assuming
116 the default rounding mode, we don't have to worry about the
117 rounding error when computing 'ns' above, since the error won't
118 cause 'ns' to drop below an integer boundary. */
119 ts_sleep.tv_nsec += (ts_sleep.tv_nsec < ns);
121 /* Normalize the interval length. nanosleep requires this. */
122 if (1000000000 <= ts_sleep.tv_nsec)
124 time_t t = ts_sleep.tv_sec + 1;
126 /* Detect integer overflow. */
127 overflow |= (t < ts_sleep.tv_sec);
129 ts_sleep.tv_sec = t;
130 ts_sleep.tv_nsec -= 1000000000;
133 /* Compute the time until which we should sleep. */
134 ts_stop.tv_sec = ts_start.tv_sec + ts_sleep.tv_sec;
135 ts_stop.tv_nsec = ts_start.tv_nsec + ts_sleep.tv_nsec;
136 if (1000000000 <= ts_stop.tv_nsec)
138 ++ts_stop.tv_sec;
139 ts_stop.tv_nsec -= 1000000000;
142 /* Detect integer overflow. */
143 overflow |= (ts_stop.tv_sec < ts_start.tv_sec
144 || (ts_stop.tv_sec == ts_start.tv_sec
145 && ts_stop.tv_nsec < ts_start.tv_nsec));
147 if (overflow)
149 /* Fix ts_sleep and ts_stop, which may be garbage due to overflow. */
150 ts_sleep.tv_sec = ts_stop.tv_sec = TIME_T_MAX;
151 ts_sleep.tv_nsec = ts_stop.tv_nsec = 999999999;
154 while (nanosleep (&ts_sleep, NULL) != 0)
156 if (errno != EINTR || gettime (&ts_start) != 0)
157 return -1;
159 /* POSIX.1-2001 requires that when a process is suspended, then
160 resumed, nanosleep (A, B) returns -1, sets errno to EINTR,
161 and sets *B to the time remaining at the point of resumption.
162 However, some versions of the Linux kernel incorrectly return
163 the time remaining at the point of suspension. Work around
164 this bug by computing the remaining time here, rather than by
165 relying on nanosleep's computation. */
167 if (! timespec_subtract (&ts_sleep, &ts_stop, &ts_start))
168 break;
171 return 0;