]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/include/timevalops.h
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / include / timevalops.h
1 /*
2  * timevalops.h -- calculations on 'struct timeval' values
3  *
4  * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
5  * The contents of 'html/copyright.html' apply.
6  *
7  * For a rationale look at 'timespecops.h'; we do the same here, but the
8  * normalisation keeps the microseconds in [0 .. 10^6[, of course.
9  */
10 #ifndef TIMEVALOPS_H
11 #define TIMEVALOPS_H
12
13 #include <sys/types.h>
14 #include <stdio.h>
15
16 #include "ntp.h"
17 #include "timetoa.h"
18
19
20 /* microseconds per second */
21 #define MICROSECONDS 1000000
22
23 #ifndef HAVE_U_INT64
24 # define USE_TSF_USEC_TABLES
25 #endif
26
27 /*
28  * Convert usec to a time stamp fraction.
29  */
30 #ifdef USE_TSF_USEC_TABLES
31 extern const u_int32 ustotslo[];
32 extern const u_int32 ustotsmid[];
33 extern const u_int32 ustotshi[];
34
35 # define TVUTOTSF(tvu, tsf)                                             \
36          ((tsf) = ustotslo[(tvu) & 0xff]                                \
37                   + ustotsmid[((tvu) >> 8) & 0xff]                      \
38                   + ustotshi[((tvu) >> 16) & 0xf])
39 #else
40 # define TVUTOTSF(tvu, tsf)                                             \
41         ((tsf) = (u_int32)                                              \
42                  ((((u_int64)(tvu) << 32) + MICROSECONDS / 2) /         \
43                   MICROSECONDS))
44 #endif
45
46 /*
47  * Convert a time stamp fraction to microseconds.  The time stamp
48  * fraction is assumed to be unsigned.
49  */
50 #ifdef USE_TSF_USEC_TABLES
51 extern const u_int32 tstouslo[256];
52 extern const u_int32 tstousmid[256];
53 extern const u_int32 tstoushi[128];
54
55 /*
56  * TV_SHIFT is used to turn the table result into a usec value.  To
57  * round, add in TV_ROUNDBIT before shifting.
58  */
59 #define TV_SHIFT        3
60 #define TV_ROUNDBIT     0x4
61
62 # define TSFTOTVU(tsf, tvu)                                             \
63          ((tvu) = (tstoushi[((tsf) >> 24) & 0xff]                       \
64                   + tstousmid[((tsf) >> 16) & 0xff]                     \
65                   + tstouslo[((tsf) >> 9) & 0x7f]                       \
66                   + TV_ROUNDBIT) >> TV_SHIFT)
67 #else
68 # define TSFTOTVU(tsf, tvu)                                             \
69          ((tvu) = (int32)                                               \
70                   (((u_int64)(tsf) * MICROSECONDS + 0x80000000) >> 32))
71 #endif
72
73 /*
74  * Convert a struct timeval to a time stamp.
75  */
76 #define TVTOTS(tv, ts) \
77         do { \
78                 (ts)->l_ui = (u_long)(tv)->tv_sec; \
79                 TVUTOTSF((tv)->tv_usec, (ts)->l_uf); \
80         } while (FALSE)
81
82 #define sTVTOTS(tv, ts) \
83         do { \
84                 int isneg = 0; \
85                 long usec; \
86                 (ts)->l_ui = (tv)->tv_sec; \
87                 usec = (tv)->tv_usec; \
88                 if (((tv)->tv_sec < 0) || ((tv)->tv_usec < 0)) { \
89                         usec = -usec; \
90                         (ts)->l_ui = -(ts)->l_ui; \
91                         isneg = 1; \
92                 } \
93                 TVUTOTSF(usec, (ts)->l_uf); \
94                 if (isneg) { \
95                         L_NEG((ts)); \
96                 } \
97         } while (FALSE)
98
99 /*
100  * Convert a time stamp to a struct timeval.  The time stamp
101  * has to be positive.
102  */
103 #define TSTOTV(ts, tv) \
104         do { \
105                 (tv)->tv_sec = (ts)->l_ui; \
106                 TSFTOTVU((ts)->l_uf, (tv)->tv_usec); \
107                 if ((tv)->tv_usec == 1000000) { \
108                         (tv)->tv_sec++; \
109                         (tv)->tv_usec = 0; \
110                 } \
111         } while (FALSE)
112
113
114 /*
115  * predicate: returns TRUE if the microseconds are in nominal range
116  * use like: int timeval_isnormal(const struct timeval *x)
117  */
118 #define timeval_isnormal(x) \
119         ((x)->tv_usec >= 0 && (x)->tv_usec < MICROSECONDS)
120
121 /*
122  * Convert milliseconds to a time stamp fraction.  Unused except for
123  * refclock_leitch.c, so accompanying lookup tables were removed in
124  * favor of reusing the microseconds conversion tables.
125  */
126 #define MSUTOTSF(msu, tsf)      TVUTOTSF((msu) * 1000, tsf)
127
128 /*
129  * predicate: returns TRUE if the microseconds are out-of-bounds
130  * use like: int timeval_isdenormal(const struct timeval *x)
131  */
132 #define timeval_isdenormal(x)   (!timeval_isnormal(x))
133
134 /* make sure microseconds are in nominal range */
135 static inline struct timeval
136 normalize_tval(
137         struct timeval  x
138         )
139 {
140         long            z;
141
142         /*
143          * If the fraction becomes excessive denormal, we use division
144          * to do first partial normalisation. The normalisation loops
145          * following will do the remaining cleanup. Since the size of
146          * tv_usec has a peculiar definition by the standard the range
147          * check is coded manually. And labs() is intentionally not used
148          * here: it has implementation-defined behaviour when applied
149          * to LONG_MIN.
150          */
151         if (x.tv_usec < -3l * MICROSECONDS ||
152             x.tv_usec >  3l * MICROSECONDS  ) {
153                 z = x.tv_usec / MICROSECONDS;
154                 x.tv_usec -= z * MICROSECONDS;
155                 x.tv_sec += z;
156         }
157
158         /*
159          * Do any remaining normalisation steps in loops. This takes 3
160          * steps max, and should outperform a division even if the
161          * mul-by-inverse trick is employed. (It also does the floor
162          * division adjustment if the above division was executed.)
163          */
164         if (x.tv_usec < 0)
165                 do {
166                         x.tv_usec += MICROSECONDS;
167                         x.tv_sec--;
168                 } while (x.tv_usec < 0);
169         else if (x.tv_usec >= MICROSECONDS)
170                 do {
171                         x.tv_usec -= MICROSECONDS;
172                         x.tv_sec++;
173                 } while (x.tv_usec >= MICROSECONDS);
174
175         return x;
176 }
177
178 /* x = a + b */
179 static inline struct timeval
180 add_tval(
181         struct timeval  a,
182         struct timeval  b
183         )
184 {
185         struct timeval  x;
186
187         x = a;
188         x.tv_sec += b.tv_sec;
189         x.tv_usec += b.tv_usec;
190
191         return normalize_tval(x);
192 }
193
194 /* x = a + b, b is fraction only */
195 static inline struct timeval
196 add_tval_us(
197         struct timeval  a,
198         long            b
199         )
200 {
201         struct timeval x;
202
203         x = a;
204         x.tv_usec += b;
205
206         return normalize_tval(x);
207 }
208
209 /* x = a - b */
210 static inline struct timeval
211 sub_tval(
212         struct timeval  a,
213         struct timeval  b
214         )
215 {       
216         struct timeval  x;
217
218         x = a;
219         x.tv_sec -= b.tv_sec;
220         x.tv_usec -= b.tv_usec;
221
222         return normalize_tval(x);
223 }
224
225 /* x = a - b, b is fraction only */
226 static inline struct timeval
227 sub_tval_us(
228         struct timeval  a,
229         long            b
230         )
231 {
232         struct timeval x;
233
234         x = a;
235         x.tv_usec -= b;
236
237         return normalize_tval(x);
238 }
239
240 /* x = -a */
241 static inline struct timeval
242 neg_tval(
243         struct timeval  a
244         )
245 {       
246         struct timeval  x;
247
248         x.tv_sec = -a.tv_sec;
249         x.tv_usec = -a.tv_usec;
250
251         return normalize_tval(x);
252 }
253
254 /* x = abs(a) */
255 static inline struct timeval
256 abs_tval(
257         struct timeval  a
258         )
259 {
260         struct timeval  c;
261
262         c = normalize_tval(a);
263         if (c.tv_sec < 0) {
264                 if (c.tv_usec != 0) {
265                         c.tv_sec = -c.tv_sec - 1;
266                         c.tv_usec = MICROSECONDS - c.tv_usec;
267                 } else {
268                         c.tv_sec = -c.tv_sec;
269                 }
270         }
271
272         return c;
273 }
274
275 /*
276  * compare previously-normalised a and b
277  * return 1 / 0 / -1 if a < / == / > b
278  */
279 static inline int
280 cmp_tval(
281         struct timeval a,
282         struct timeval b
283         )
284 {
285         int r;
286
287         r = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec);
288         if (0 == r)
289                 r = (a.tv_usec > b.tv_usec) -
290                     (a.tv_usec < b.tv_usec);
291         
292         return r;
293 }
294
295 /*
296  * compare possibly-denormal a and b
297  * return 1 / 0 / -1 if a < / == / > b
298  */
299 static inline int
300 cmp_tval_denorm(
301         struct timeval  a,
302         struct timeval  b
303         )
304 {
305         return cmp_tval(normalize_tval(a), normalize_tval(b));
306 }
307
308 /*
309  * test previously-normalised a
310  * return 1 / 0 / -1 if a < / == / > 0
311  */
312 static inline int
313 test_tval(
314         struct timeval  a
315         )
316 {
317         int             r;
318
319         r = (a.tv_sec > 0) - (a.tv_sec < 0);
320         if (r == 0)
321                 r = (a.tv_usec > 0);
322         
323         return r;
324 }
325
326 /*
327  * test possibly-denormal a
328  * return 1 / 0 / -1 if a < / == / > 0
329  */
330 static inline int
331 test_tval_denorm(
332         struct timeval  a
333         )
334 {
335         return test_tval(normalize_tval(a));
336 }
337
338 /* return LIB buffer ptr to string rep */
339 static inline const char *
340 tvaltoa(
341         struct timeval  x
342         )
343 {
344         return format_time_fraction(x.tv_sec, x.tv_usec, 6);
345 }
346
347 /* convert from timeval duration to l_fp duration */
348 static inline l_fp
349 tval_intv_to_lfp(
350         struct timeval  x
351         )
352 {
353         struct timeval  v;
354         l_fp            y;
355         
356         v = normalize_tval(x);
357         TVUTOTSF(v.tv_usec, y.l_uf);
358         y.l_i = (int32)v.tv_sec;
359
360         return y;
361 }
362
363 /* x must be UN*X epoch, output *y will be in NTP epoch */
364 static inline l_fp
365 tval_stamp_to_lfp(
366         struct timeval  x
367         )
368 {
369         l_fp            y;
370
371         y = tval_intv_to_lfp(x);
372         y.l_ui += JAN_1970;
373
374         return y;
375 }
376
377 /* convert to l_fp type, relative signed/unsigned and absolute */
378 static inline struct timeval
379 lfp_intv_to_tval(
380         l_fp            x
381         )
382 {
383         struct timeval  out;
384         l_fp            absx;
385         int             neg;
386         
387         neg = L_ISNEG(&x);
388         absx = x;
389         if (neg) {
390                 L_NEG(&absx);   
391         }
392         TSFTOTVU(absx.l_uf, out.tv_usec);
393         out.tv_sec = absx.l_i;
394         if (neg) {
395                 out.tv_sec = -out.tv_sec;
396                 out.tv_usec = -out.tv_usec;
397                 out = normalize_tval(out);
398         }
399
400         return out;
401 }
402
403 static inline struct timeval
404 lfp_uintv_to_tval(
405         l_fp            x
406         )
407 {
408         struct timeval  out;
409         
410         TSFTOTVU(x.l_uf, out.tv_usec);
411         out.tv_sec = x.l_ui;
412
413         return out;
414 }
415
416 /*
417  * absolute (timestamp) conversion. Input is time in NTP epoch, output
418  * is in UN*X epoch. The NTP time stamp will be expanded around the
419  * pivot time *p or the current time, if p is NULL.
420  */
421 static inline struct timeval
422 lfp_stamp_to_tval(
423         l_fp            x,
424         const time_t *  p
425         )
426 {
427         struct timeval  out;
428         vint64          sec;
429
430         sec = ntpcal_ntp_to_time(x.l_ui, p);
431         TSFTOTVU(x.l_uf, out.tv_usec);
432
433         /* copying a vint64 to a time_t needs some care... */
434 #if SIZEOF_TIME_T <= 4
435         out.tv_sec = (time_t)sec.d_s.lo;
436 #elif defined(HAVE_INT64)
437         out.tv_sec = (time_t)sec.q_s;
438 #else
439         out.tv_sec = ((time_t)sec.d_s.hi << 32) | sec.d_s.lo;
440 #endif
441         out = normalize_tval(out);
442
443         return out;
444 }
445
446 #endif  /* TIMEVALOPS_H */