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 */ 447