*** empty log message ***
[coreutils.git] / lib / xnanosleep.c
blobca8727bd0462d8261c9041dca1276ae5314a1d23
1 /* xnanosleep.c -- a more convenient interface to nanosleep
2 Copyright (C) 2002 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 <stdio.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <time.h>
31 #define USE_CLOCK_GETTIME (defined CLOCK_REALTIME && HAVE_CLOCK_GETTIME)
32 #if ! USE_CLOCK_GETTIME
33 # include <sys/time.h>
34 #endif
36 #ifndef CHAR_BIT
37 # define CHAR_BIT 8
38 #endif
40 /* The extra casts work around common compiler bugs. */
41 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
42 /* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
43 It is necessary at least when t == time_t. */
44 #define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
45 ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
46 #define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
48 #ifndef TIME_T_MAX
49 # define TIME_T_MAX TYPE_MAXIMUM (time_t)
50 #endif
52 #include "timespec.h"
53 #include "xalloc.h"
54 #include "xnanosleep.h"
55 #include "xstrtod.h"
57 /* Subtract the `struct timespec' values X and Y,
58 storing the difference in DIFF.
59 Return 1 if the difference is positive, otherwise 0.
60 Derived from code in the GNU libc manual. */
62 static int
63 timespec_subtract (struct timespec *diff,
64 const struct timespec *x, struct timespec *y)
66 /* Perform the carry for the later subtraction by updating Y. */
67 if (x->tv_nsec < y->tv_nsec)
69 int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
70 y->tv_nsec -= 1000000000 * nsec;
71 y->tv_sec += nsec;
74 if (1000000000 < x->tv_nsec - y->tv_nsec)
76 int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000;
77 y->tv_nsec += 1000000000 * nsec;
78 y->tv_sec -= nsec;
81 /* Compute the time remaining to wait.
82 `tv_nsec' is certainly positive. */
83 diff->tv_sec = x->tv_sec - y->tv_sec;
84 diff->tv_nsec = x->tv_nsec - y->tv_nsec;
86 /* Return 1 if result is positive. */
87 return y->tv_sec < x->tv_sec;
90 struct timespec *
91 clock_get_realtime (struct timespec *ts)
93 int fail;
94 #if USE_CLOCK_GETTIME
95 fail = clock_gettime (CLOCK_REALTIME, ts);
96 #else
97 struct timeval tv;
98 fail = gettimeofday (&tv, NULL);
99 if (!fail)
101 ts->tv_sec = tv.tv_sec;
102 ts->tv_nsec = 1000 * tv.tv_usec;
104 #endif
106 if (fail)
107 return NULL;
109 return ts;
112 /* Sleep until the time (call it WAKE_UP_TIME) specified as
113 SECONDS seconds after the time this function is called.
114 SECONDS must be non-negative. If SECONDS is so large that
115 it is not representable as a `struct timespec', then use
116 the maximum value for that interval. Return -1 on failure
117 (setting errno), 0 on success. */
120 xnanosleep (double seconds)
122 int overflow;
123 double ns;
124 struct timespec ts_start;
125 struct timespec ts_sleep;
126 struct timespec ts_stop;
128 assert (0 <= seconds);
130 if (clock_get_realtime (&ts_start) == NULL)
131 return -1;
133 /* Separate whole seconds from nanoseconds.
134 Be careful to detect any overflow. */
135 ts_sleep.tv_sec = seconds;
136 ns = 1e9 * (seconds - ts_sleep.tv_sec);
137 overflow = ! (ts_sleep.tv_sec <= seconds && 0 <= ns && ns <= 1e9);
138 ts_sleep.tv_nsec = ns;
140 /* Round up to the next whole number, if necessary, so that we
141 always sleep for at least the requested amount of time. Assuming
142 the default rounding mode, we don't have to worry about the
143 rounding error when computing 'ns' above, since the error won't
144 cause 'ns' to drop below an integer boundary. */
145 ts_sleep.tv_nsec += (ts_sleep.tv_nsec < ns);
147 /* Normalize the interval length. nanosleep requires this. */
148 if (1000000000 <= ts_sleep.tv_nsec)
150 time_t t = ts_sleep.tv_sec + 1;
152 /* Detect integer overflow. */
153 overflow |= (t < ts_sleep.tv_sec);
155 ts_sleep.tv_sec = t;
156 ts_sleep.tv_nsec -= 1000000000;
159 /* Compute the time until which we should sleep. */
160 ts_stop.tv_sec = ts_start.tv_sec + ts_sleep.tv_sec;
161 ts_stop.tv_nsec = ts_start.tv_nsec + ts_sleep.tv_nsec;
162 if (1000000000 <= ts_stop.tv_nsec)
164 ++ts_stop.tv_sec;
165 ts_stop.tv_nsec -= 1000000000;
168 /* Detect integer overflow. */
169 overflow |= (ts_stop.tv_sec < ts_start.tv_sec
170 || (ts_stop.tv_sec == ts_start.tv_sec
171 && ts_stop.tv_nsec < ts_start.tv_nsec));
173 if (overflow)
175 /* Fix ts_sleep and ts_stop, which may be garbage due to overflow. */
176 ts_sleep.tv_sec = ts_stop.tv_sec = TIME_T_MAX;
177 ts_sleep.tv_nsec = ts_stop.tv_nsec = 999999999;
180 while (nanosleep (&ts_sleep, NULL) != 0)
182 if (errno != EINTR)
183 return -1;
185 /* POSIX.1-2001 requires that when a process is suspended, then
186 resumed, nanosleep (A, B) returns -1, sets errno to EINTR,
187 and sets *B to the time remaining at the point of resumption.
188 However, some versions of the Linux kernel incorrectly return
189 the time remaining at the point of suspension. Work around
190 this bug by computing the remaining time here, rather than by
191 relying on nanosleep's computation. */
193 if (! timespec_subtract (&ts_sleep, &ts_stop,
194 clock_get_realtime (&ts_start)))
195 break;
198 return 0;