blob: 770974ca00980c8eba57257febac3a86235e73a3 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
Willy Tarreau2dd0d472006-06-29 17:53:05 +02002 include/common/time.h
Willy Tarreaubaaee002006-06-26 02:48:02 +02003 Time calculation functions and macros.
4
Willy Tarreau42aae5c2007-04-29 17:43:56 +02005 Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu
Willy Tarreaubaaee002006-06-26 02:48:02 +02006
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation, version 2.1
10 exclusively.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20*/
21
Willy Tarreau2dd0d472006-06-29 17:53:05 +020022#ifndef _COMMON_TIME_H
23#define _COMMON_TIME_H
Willy Tarreaubaaee002006-06-26 02:48:02 +020024
25#include <stdlib.h>
26#include <sys/time.h>
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020027#include <common/config.h>
Willy Tarreau42aae5c2007-04-29 17:43:56 +020028#include <common/standard.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020029
Willy Tarreaua6a6a932007-04-28 22:40:08 +020030/* eternity when exprimed in timeval */
31#ifndef TV_ETERNITY
32#define TV_ETERNITY (~0UL)
33#endif
34
35/* eternity when exprimed in ms */
36#ifndef TV_ETERNITY_MS
37#define TV_ETERNITY_MS (-1)
38#endif
39
40#define TIME_ETERNITY (TV_ETERNITY_MS)
41
Willy Tarreaubaaee002006-06-26 02:48:02 +020042
43/* returns the lowest delay amongst <old> and <new>, and respects TIME_ETERNITY */
44#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
45#define SETNOW(a) (*a=now)
46
47extern struct timeval now; /* the current date at any moment */
48extern struct timeval start_date; /* the process's start date */
49
50
Willy Tarreau42aae5c2007-04-29 17:43:56 +020051/**** exported functions *************************************************/
52
53
Willy Tarreaubaaee002006-06-26 02:48:02 +020054/*
55 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
56 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +020057REGPRM3 struct timeval *tv_ms_add(struct timeval *tv, const struct timeval *from, int ms);
Willy Tarreaubaaee002006-06-26 02:48:02 +020058
59/*
60 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
Willy Tarreau42aae5c2007-04-29 17:43:56 +020061 * Must not be used when either argument is eternity. Use tv_ms_cmp2() for that.
Willy Tarreaubaaee002006-06-26 02:48:02 +020062 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +020063REGPRM2 int tv_ms_cmp(const struct timeval *tv1, const struct timeval *tv2);
Willy Tarreaubaaee002006-06-26 02:48:02 +020064
65/*
Willy Tarreau8d7d1492007-04-29 10:50:43 +020066 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
67 * assuming that TV_ETERNITY is greater than everything.
Willy Tarreaubaaee002006-06-26 02:48:02 +020068 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +020069REGPRM2 int tv_ms_cmp2(const struct timeval *tv1, const struct timeval *tv2);
Willy Tarreau5e8f0662007-02-12 00:59:08 +010070
Willy Tarreau42aae5c2007-04-29 17:43:56 +020071/**** general purpose functions and macros *******************************/
72
73
74/* tv_now: sets <tv> to the current time */
75REGPRM1 static inline struct timeval *tv_now(struct timeval *tv)
76{
77 gettimeofday(tv, NULL);
78 return tv;
79}
Willy Tarreaubaaee002006-06-26 02:48:02 +020080
81/*
Willy Tarreau42aae5c2007-04-29 17:43:56 +020082 * sets a struct timeval to its highest value so that it can never happen
83 * note that only tv_usec is necessary to detect it since a tv_usec > 999999
84 * is normally not possible.
85 *
Willy Tarreaubaaee002006-06-26 02:48:02 +020086 */
Willy Tarreaubaaee002006-06-26 02:48:02 +020087
Willy Tarreau42aae5c2007-04-29 17:43:56 +020088REGPRM1 static inline struct timeval *tv_eternity(struct timeval *tv)
Willy Tarreaubaaee002006-06-26 02:48:02 +020089{
Willy Tarreau42aae5c2007-04-29 17:43:56 +020090 tv->tv_sec = tv->tv_usec = TV_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +020091 return tv;
92}
93
94/*
Willy Tarreau42aae5c2007-04-29 17:43:56 +020095 * sets a struct timeval to 0
96 *
Willy Tarreaubaaee002006-06-26 02:48:02 +020097 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +020098REGPRM1 static inline struct timeval *tv_zero(struct timeval *tv) {
99 tv->tv_sec = tv->tv_usec = 0;
100 return tv;
101}
102
103/*
104 * returns non null if tv is [eternity], otherwise 0.
105 */
106#define tv_iseternity(tv) ((tv)->tv_usec == TV_ETERNITY)
107
108/*
109 * returns non null if tv is [0], otherwise 0.
110 */
111#define tv_iszero(tv) (((tv)->tv_sec | (tv)->tv_usec) == 0)
112
113
114/**** comparision functions and macros ***********************************/
115
116
117/* tv_cmp: compares <tv1> and <tv2> : returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2. */
118REGPRM2 static inline int __tv_cmp(const struct timeval *tv1, const struct timeval *tv2)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200119{
Willy Tarreaua6a6a932007-04-28 22:40:08 +0200120 if ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200121 return -1;
Willy Tarreaua6a6a932007-04-28 22:40:08 +0200122 else if ((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200123 return 1;
Willy Tarreaua6a6a932007-04-28 22:40:08 +0200124 else if ((unsigned)tv1->tv_usec < (unsigned)tv2->tv_usec)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200125 return -1;
Willy Tarreaua6a6a932007-04-28 22:40:08 +0200126 else if ((unsigned)tv1->tv_usec > (unsigned)tv2->tv_usec)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200127 return 1;
128 else
129 return 0;
Willy Tarreau5e8f0662007-02-12 00:59:08 +0100130}
131
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200132/* tv_iseq: compares <tv1> and <tv2> : returns 1 if tv1 == tv2, otherwise 0 */
133REGPRM2 static inline int __tv_iseq(const struct timeval *tv1, const struct timeval *tv2)
134{
135 return ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) &&
136 ((unsigned)tv1->tv_usec == (unsigned)tv2->tv_usec);
137}
138
139/* tv_isgt: compares <tv1> and <tv2> : returns 1 if tv1 > tv2, otherwise 0 */
140REGPRM2 static inline int __tv_isgt(const struct timeval *tv1, const struct timeval *tv2)
141{
142 return
143 ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) ?
144 ((unsigned)tv1->tv_usec > (unsigned)tv2->tv_usec) :
145 ((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec);
146}
147
148/* tv_isge: compares <tv1> and <tv2> : returns 1 if tv1 >= tv2, otherwise 0 */
149REGPRM2 static inline int __tv_isge(const struct timeval *tv1, const struct timeval *tv2)
150{
151 return
152 ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) ?
153 ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec) :
154 ((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec);
155}
156
157/* tv_islt: compares <tv1> and <tv2> : returns 1 if tv1 < tv2, otherwise 0 */
158REGPRM2 static inline int __tv_islt(const struct timeval *tv1, const struct timeval *tv2)
159{
160 return
161 ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) ?
162 ((unsigned)tv1->tv_usec < (unsigned)tv2->tv_usec) :
163 ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec);
164}
165
166/* tv_isle: compares <tv1> and <tv2> : returns 1 if tv1 <= tv2, otherwise 0 */
167REGPRM2 static inline int __tv_isle(const struct timeval *tv1, const struct timeval *tv2)
168{
169 return
170 ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) ?
171 ((unsigned)tv1->tv_usec <= (unsigned)tv2->tv_usec) :
172 ((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec);
173}
174
Willy Tarreau5e8f0662007-02-12 00:59:08 +0100175/*
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200176 * compares <tv1> and <tv2> modulo 1ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2
177 * Must not be used when either argument is eternity. Use tv_ms_cmp2() for that.
Willy Tarreau5e8f0662007-02-12 00:59:08 +0100178 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200179#define tv_ms_cmp _tv_ms_cmp
180REGPRM2 int _tv_ms_cmp(const struct timeval *tv1, const struct timeval *tv2);
181REGPRM2 static inline int __tv_ms_cmp(const struct timeval *tv1, const struct timeval *tv2)
Willy Tarreau5e8f0662007-02-12 00:59:08 +0100182{
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200183 if ((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec) {
184 if ((unsigned)tv2->tv_usec >= (unsigned)tv1->tv_usec + 1000)
185 return -1;
186 else if ((unsigned)tv1->tv_usec >= (unsigned)tv2->tv_usec + 1000)
187 return 1;
188 else
189 return 0;
190 }
191 else if (((unsigned)tv2->tv_sec > (unsigned)tv1->tv_sec + 1) ||
192 (((unsigned)tv2->tv_sec == (unsigned)tv1->tv_sec + 1) &&
193 ((unsigned)tv2->tv_usec + 1000000 >= (unsigned)tv1->tv_usec + 1000)))
194 return -1;
195 else if (((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec + 1) ||
196 (((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec + 1) &&
197 ((unsigned)tv1->tv_usec + 1000000 >= (unsigned)tv2->tv_usec + 1000)))
Willy Tarreau5e8f0662007-02-12 00:59:08 +0100198 return 1;
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200199 else
Willy Tarreau5e8f0662007-02-12 00:59:08 +0100200 return 0;
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200201}
202
203/*
204 * compares <tv1> and <tv2> modulo 1 ms: returns 0 if equal, -1 if tv1 < tv2, 1 if tv1 > tv2,
205 * assuming that TV_ETERNITY is greater than everything.
206 */
207#define tv_ms_cmp2 _tv_ms_cmp2
208REGPRM2 int _tv_ms_cmp2(const struct timeval *tv1, const struct timeval *tv2);
209REGPRM2 static inline int __tv_ms_cmp2(const struct timeval *tv1, const struct timeval *tv2)
210{
211 if (tv_iseternity(tv1))
212 if (tv_iseternity(tv2))
213 return 0; /* same */
214 else
215 return 1; /* tv1 later than tv2 */
216 else if (tv_iseternity(tv2))
217 return -1; /* tv2 later than tv1 */
218 return tv_ms_cmp(tv1, tv2);
219}
220
221/*
222 * compares <tv1> and <tv2> modulo 1 ms: returns 1 if tv1 <= tv2, 0 if tv1 > tv2,
223 * assuming that TV_ETERNITY is greater than everything. Returns 0 if tv1 is
224 * TV_ETERNITY, and always assumes that tv2 != TV_ETERNITY. Designed to replace
225 * occurrences of (tv_ms_cmp2(tv,now) <= 0).
226 */
227#define tv_ms_le2 _tv_ms_le2
228REGPRM2 int _tv_ms_le2(const struct timeval *tv1, const struct timeval *tv2);
229REGPRM2 static inline int __tv_ms_le2(const struct timeval *tv1, const struct timeval *tv2)
230{
231 if (likely((unsigned)tv1->tv_sec > (unsigned)tv2->tv_sec + 1))
232 return 0;
233
234 if (likely((unsigned)tv1->tv_sec < (unsigned)tv2->tv_sec))
235 return 1;
236
237 if (likely((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec)) {
238 if ((unsigned)tv2->tv_usec >= (unsigned)tv1->tv_usec + 1000)
239 return 1;
240 else
241 return 0;
242 }
243
244 if (unlikely(((unsigned)tv1->tv_sec == (unsigned)tv2->tv_sec + 1) &&
245 ((unsigned)tv1->tv_usec + 1000000 >= (unsigned)tv2->tv_usec + 1000)))
246 return 0;
247 else
Willy Tarreau5e8f0662007-02-12 00:59:08 +0100248 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200249}
250
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200251
252/**** operators **********************************************************/
253
254
Willy Tarreaubaaee002006-06-26 02:48:02 +0200255/*
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200256 * Returns the time in ms elapsed between tv1 and tv2, assuming that tv1<=tv2.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200257 * Must not be used when either argument is eternity.
258 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200259#define tv_ms_elapsed __tv_ms_elapsed
260REGPRM2 unsigned long _tv_ms_elapsed(const struct timeval *tv1, const struct timeval *tv2);
261REGPRM2 static inline unsigned long __tv_ms_elapsed(const struct timeval *tv1, const struct timeval *tv2)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200262{
263 unsigned long ret;
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200264
265 ret = ((signed long)(tv2->tv_sec - tv1->tv_sec)) * 1000;
266 ret += ((signed long)(tv2->tv_usec - tv1->tv_usec)) / 1000;
267 return ret;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200268}
269
270/*
271 * returns the remaining time between tv1=now and event=tv2
272 * if tv2 is passed, 0 is returned.
273 * Must not be used when either argument is eternity.
274 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200275
276#define tv_ms_remain __tv_ms_remain
277REGPRM2 unsigned long _tv_ms_remain(const struct timeval *tv1, const struct timeval *tv2);
278REGPRM2 static inline unsigned long __tv_ms_remain(const struct timeval *tv1, const struct timeval *tv2)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200279{
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200280 if (tv_ms_cmp(tv1, tv2) >= 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200281 return 0; /* event elapsed */
282
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200283 return __tv_ms_elapsed(tv1, tv2);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200284}
285
Willy Tarreaubaaee002006-06-26 02:48:02 +0200286/*
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200287 * returns the remaining time between tv1=now and event=tv2
288 * if tv2 is passed, 0 is returned.
289 * Returns TIME_ETERNITY if tv2 is eternity.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200290 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200291#define tv_ms_remain2 _tv_ms_remain2
292REGPRM2 unsigned long _tv_ms_remain2(const struct timeval *tv1, const struct timeval *tv2);
293REGPRM2 static inline unsigned long __tv_ms_remain2(const struct timeval *tv1, const struct timeval *tv2)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200294{
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200295 if (tv_iseternity(tv2))
296 return TIME_ETERNITY;
297
298 return tv_ms_remain(tv1, tv2);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200299}
300
301/*
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200302 * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
Willy Tarreaubaaee002006-06-26 02:48:02 +0200303 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200304#define tv_ms_add _tv_ms_add
305REGPRM3 struct timeval *_tv_ms_add(struct timeval *tv, const struct timeval *from, int ms);
306REGPRM3 static inline struct timeval *__tv_ms_add(struct timeval *tv, const struct timeval *from, int ms)
307{
308 tv->tv_usec = from->tv_usec + (ms % 1000) * 1000;
309 tv->tv_sec = from->tv_sec + (ms / 1000);
310 while (tv->tv_usec >= 1000000) {
311 tv->tv_usec -= 1000000;
312 tv->tv_sec++;
313 }
Willy Tarreaua6a6a932007-04-28 22:40:08 +0200314 return tv;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200315}
316
Willy Tarreaubaaee002006-06-26 02:48:02 +0200317
Willy Tarreaua6a6a932007-04-28 22:40:08 +0200318/*
319 * compares <tv1> and <tv2> : returns 1 if <tv1> is before <tv2>, otherwise 0.
320 * This should be very fast because it's used in schedulers.
321 * It has been optimized to return 1 (so call it in a loop which continues
322 * as long as tv1<=tv2)
323 */
324
325#define tv_isbefore(tv1, tv2) \
326 (unlikely((unsigned)(tv1)->tv_sec < (unsigned)(tv2)->tv_sec) ? 1 : \
327 (unlikely((unsigned)(tv1)->tv_sec > (unsigned)(tv2)->tv_sec) ? 0 : \
328 unlikely((unsigned)(tv1)->tv_usec < (unsigned)(tv2)->tv_usec)))
329
330/*
331 * returns the first event between <tv1> and <tv2> into <tvmin>.
332 * a zero tv is ignored. <tvmin> is returned. If <tvmin> is known
333 * to be the same as <tv1> or <tv2>, it is recommended to use
334 * tv_bound instead.
335 */
336#define tv_min(tvmin, tv1, tv2) ({ \
337 if (tv_isbefore(tv1, tv2)) { \
338 *tvmin = *tv1; \
339 } \
340 else { \
341 *tvmin = *tv2; \
342 } \
343 tvmin; \
344})
345
346/*
347 * returns the first event between <tv1> and <tv2> into <tvmin>.
348 * a zero tv is ignored. <tvmin> is returned. This function has been
349 * optimized to be called as tv_min(a,a,b) or tv_min(b,a,b).
350 */
351#define tv_bound(tv1, tv2) ({ \
352 if (tv_isbefore(tv2, tv1)) \
353 *tv1 = *tv2; \
354 tv1; \
355})
Willy Tarreaubaaee002006-06-26 02:48:02 +0200356
357
Willy Tarreau2dd0d472006-06-29 17:53:05 +0200358#endif /* _COMMON_TIME_H */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200359
360/*
361 * Local variables:
362 * c-indent-level: 8
363 * c-basic-offset: 8
364 * End:
365 */