/src/ntp-dev/include/timevalops.h
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
140 | 0 | long z; |
141 | 0 |
|
142 | 0 | /* |
143 | 0 | * If the fraction becomes excessive denormal, we use division |
144 | 0 | * to do first partial normalisation. The normalisation loops |
145 | 0 | * following will do the remaining cleanup. Since the size of |
146 | 0 | * tv_usec has a peculiar definition by the standard the range |
147 | 0 | * check is coded manually. And labs() is intentionally not used |
148 | 0 | * here: it has implementation-defined behaviour when applied |
149 | 0 | * to LONG_MIN. |
150 | 0 | */ |
151 | 0 | if (x.tv_usec < -3l * MICROSECONDS || |
152 | 0 | x.tv_usec > 3l * MICROSECONDS ) { |
153 | 0 | z = x.tv_usec / MICROSECONDS; |
154 | 0 | x.tv_usec -= z * MICROSECONDS; |
155 | 0 | x.tv_sec += z; |
156 | 0 | } |
157 | 0 |
|
158 | 0 | /* |
159 | 0 | * Do any remaining normalisation steps in loops. This takes 3 |
160 | 0 | * steps max, and should outperform a division even if the |
161 | 0 | * mul-by-inverse trick is employed. (It also does the floor |
162 | 0 | * division adjustment if the above division was executed.) |
163 | 0 | */ |
164 | 0 | if (x.tv_usec < 0) |
165 | 0 | do { |
166 | 0 | x.tv_usec += MICROSECONDS; |
167 | 0 | x.tv_sec--; |
168 | 0 | } while (x.tv_usec < 0); |
169 | 0 | else if (x.tv_usec >= MICROSECONDS) |
170 | 0 | do { |
171 | 0 | x.tv_usec -= MICROSECONDS; |
172 | 0 | x.tv_sec++; |
173 | 0 | } while (x.tv_usec >= MICROSECONDS); |
174 | 0 |
|
175 | 0 | return x; |
176 | 0 | } |
177 | | |
178 | | /* x = a + b */ |
179 | | static inline struct timeval |
180 | | add_tval( |
181 | | struct timeval a, |
182 | | struct timeval b |
183 | | ) |
184 | 0 | { |
185 | 0 | struct timeval x; |
186 | 0 |
|
187 | 0 | x = a; |
188 | 0 | x.tv_sec += b.tv_sec; |
189 | 0 | x.tv_usec += b.tv_usec; |
190 | 0 |
|
191 | 0 | return normalize_tval(x); |
192 | 0 | } |
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 | 0 | { |
201 | 0 | struct timeval x; |
202 | 0 |
|
203 | 0 | x = a; |
204 | 0 | x.tv_usec += b; |
205 | 0 |
|
206 | 0 | return normalize_tval(x); |
207 | 0 | } |
208 | | |
209 | | /* x = a - b */ |
210 | | static inline struct timeval |
211 | | sub_tval( |
212 | | struct timeval a, |
213 | | struct timeval b |
214 | | ) |
215 | 0 | { |
216 | 0 | struct timeval x; |
217 | 0 |
|
218 | 0 | x = a; |
219 | 0 | x.tv_sec -= b.tv_sec; |
220 | 0 | x.tv_usec -= b.tv_usec; |
221 | 0 |
|
222 | 0 | return normalize_tval(x); |
223 | 0 | } |
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 | 0 | { |
232 | 0 | struct timeval x; |
233 | 0 |
|
234 | 0 | x = a; |
235 | 0 | x.tv_usec -= b; |
236 | 0 |
|
237 | 0 | return normalize_tval(x); |
238 | 0 | } |
239 | | |
240 | | /* x = -a */ |
241 | | static inline struct timeval |
242 | | neg_tval( |
243 | | struct timeval a |
244 | | ) |
245 | 0 | { |
246 | 0 | struct timeval x; |
247 | 0 |
|
248 | 0 | x.tv_sec = -a.tv_sec; |
249 | 0 | x.tv_usec = -a.tv_usec; |
250 | 0 |
|
251 | 0 | return normalize_tval(x); |
252 | 0 | } |
253 | | |
254 | | /* x = abs(a) */ |
255 | | static inline struct timeval |
256 | | abs_tval( |
257 | | struct timeval a |
258 | | ) |
259 | 0 | { |
260 | 0 | struct timeval c; |
261 | 0 |
|
262 | 0 | c = normalize_tval(a); |
263 | 0 | if (c.tv_sec < 0) { |
264 | 0 | if (c.tv_usec != 0) { |
265 | 0 | c.tv_sec = -c.tv_sec - 1; |
266 | 0 | c.tv_usec = MICROSECONDS - c.tv_usec; |
267 | 0 | } else { |
268 | 0 | c.tv_sec = -c.tv_sec; |
269 | 0 | } |
270 | 0 | } |
271 | 0 |
|
272 | 0 | return c; |
273 | 0 | } |
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 | 0 | { |
285 | 0 | int r; |
286 | 0 |
|
287 | 0 | r = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec); |
288 | 0 | if (0 == r) |
289 | 0 | r = (a.tv_usec > b.tv_usec) - |
290 | 0 | (a.tv_usec < b.tv_usec); |
291 | 0 | |
292 | 0 | return r; |
293 | 0 | } |
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 | 0 | { |
305 | 0 | return cmp_tval(normalize_tval(a), normalize_tval(b)); |
306 | 0 | } |
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 | 0 | { |
317 | 0 | int r; |
318 | 0 |
|
319 | 0 | r = (a.tv_sec > 0) - (a.tv_sec < 0); |
320 | 0 | if (r == 0) |
321 | 0 | r = (a.tv_usec > 0); |
322 | 0 | |
323 | 0 | return r; |
324 | 0 | } |
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 | 0 | { |
335 | 0 | return test_tval(normalize_tval(a)); |
336 | 0 | } |
337 | | |
338 | | /* return LIB buffer ptr to string rep */ |
339 | | static inline const char * |
340 | | tvaltoa( |
341 | | struct timeval x |
342 | | ) |
343 | 0 | { |
344 | 0 | return format_time_fraction(x.tv_sec, x.tv_usec, 6); |
345 | 0 | } |
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 | 0 | { |
353 | 0 | struct timeval v; |
354 | 0 | l_fp y; |
355 | 0 | |
356 | 0 | v = normalize_tval(x); |
357 | 0 | TVUTOTSF(v.tv_usec, y.l_uf); |
358 | 0 | y.l_i = (int32)v.tv_sec; |
359 | 0 |
|
360 | 0 | return y; |
361 | 0 | } |
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 | 0 | { |
369 | 0 | l_fp y; |
370 | 0 |
|
371 | 0 | y = tval_intv_to_lfp(x); |
372 | 0 | y.l_ui += JAN_1970; |
373 | 0 |
|
374 | 0 | return y; |
375 | 0 | } |
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 | 0 | { |
383 | 0 | struct timeval out; |
384 | 0 | l_fp absx; |
385 | 0 | int neg; |
386 | 0 | |
387 | 0 | neg = L_ISNEG(&x); |
388 | 0 | absx = x; |
389 | 0 | if (neg) { |
390 | 0 | L_NEG(&absx); |
391 | 0 | } |
392 | 0 | TSFTOTVU(absx.l_uf, out.tv_usec); |
393 | 0 | out.tv_sec = absx.l_i; |
394 | 0 | if (neg) { |
395 | 0 | out.tv_sec = -out.tv_sec; |
396 | 0 | out.tv_usec = -out.tv_usec; |
397 | 0 | out = normalize_tval(out); |
398 | 0 | } |
399 | 0 |
|
400 | 0 | return out; |
401 | 0 | } |
402 | | |
403 | | static inline struct timeval |
404 | | lfp_uintv_to_tval( |
405 | | l_fp x |
406 | | ) |
407 | 0 | { |
408 | 0 | struct timeval out; |
409 | 0 | |
410 | 0 | TSFTOTVU(x.l_uf, out.tv_usec); |
411 | 0 | out.tv_sec = x.l_ui; |
412 | 0 |
|
413 | 0 | return out; |
414 | 0 | } |
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 | 0 | { |
427 | 0 | struct timeval out; |
428 | 0 | vint64 sec; |
429 | 0 |
|
430 | 0 | sec = ntpcal_ntp_to_time(x.l_ui, p); |
431 | 0 | TSFTOTVU(x.l_uf, out.tv_usec); |
432 | 0 |
|
433 | 0 | /* copying a vint64 to a time_t needs some care... */ |
434 | 0 | #if SIZEOF_TIME_T <= 4 |
435 | 0 | out.tv_sec = (time_t)sec.d_s.lo; |
436 | 0 | #elif defined(HAVE_INT64) |
437 | 0 | out.tv_sec = (time_t)sec.q_s; |
438 | 0 | #else |
439 | 0 | out.tv_sec = ((time_t)sec.d_s.hi << 32) | sec.d_s.lo; |
440 | 0 | #endif |
441 | 0 | out = normalize_tval(out); |
442 | 0 |
|
443 | 0 | return out; |
444 | 0 | } |
445 | | |
446 | | #endif /* TIMEVALOPS_H */ |