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