timevalops.h revision 275970
1275970Scy/* 2275970Scy * timevalops.h -- calculations on 'struct timeval' values 3275970Scy * 4275970Scy * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project. 5275970Scy * The contents of 'html/copyright.html' apply. 6275970Scy * 7275970Scy * For a rationale look at 'timespecops.h'; we do the same here, but the 8275970Scy * normalisation keeps the microseconds in [0 .. 10^6[, of course. 9275970Scy */ 10275970Scy#ifndef TIMEVALOPS_H 11275970Scy#define TIMEVALOPS_H 12275970Scy 13275970Scy#include <sys/types.h> 14275970Scy#include <stdio.h> 15275970Scy 16275970Scy#include "ntp.h" 17275970Scy#include "timetoa.h" 18275970Scy 19275970Scy 20275970Scy/* microseconds per second */ 21275970Scy#define MICROSECONDS 1000000 22275970Scy 23275970Scy#ifndef HAVE_U_INT64 24275970Scy# define USE_TSF_USEC_TABLES 25275970Scy#endif 26275970Scy 27275970Scy/* 28275970Scy * Convert usec to a time stamp fraction. 29275970Scy */ 30275970Scy#ifdef USE_TSF_USEC_TABLES 31275970Scyextern const u_int32 ustotslo[]; 32275970Scyextern const u_int32 ustotsmid[]; 33275970Scyextern const u_int32 ustotshi[]; 34275970Scy 35275970Scy# define TVUTOTSF(tvu, tsf) \ 36275970Scy ((tsf) = ustotslo[(tvu) & 0xff] \ 37275970Scy + ustotsmid[((tvu) >> 8) & 0xff] \ 38275970Scy + ustotshi[((tvu) >> 16) & 0xf]) 39275970Scy#else 40275970Scy# define TVUTOTSF(tvu, tsf) \ 41275970Scy ((tsf) = (u_int32) \ 42275970Scy ((((u_int64)(tvu) << 32) + MICROSECONDS / 2) / \ 43275970Scy MICROSECONDS)) 44275970Scy#endif 45275970Scy 46275970Scy/* 47275970Scy * Convert a time stamp fraction to microseconds. The time stamp 48275970Scy * fraction is assumed to be unsigned. 49275970Scy */ 50275970Scy#ifdef USE_TSF_USEC_TABLES 51275970Scyextern const u_int32 tstouslo[256]; 52275970Scyextern const u_int32 tstousmid[256]; 53275970Scyextern const u_int32 tstoushi[128]; 54275970Scy 55275970Scy/* 56275970Scy * TV_SHIFT is used to turn the table result into a usec value. To 57275970Scy * round, add in TV_ROUNDBIT before shifting. 58275970Scy */ 59275970Scy#define TV_SHIFT 3 60275970Scy#define TV_ROUNDBIT 0x4 61275970Scy 62275970Scy# define TSFTOTVU(tsf, tvu) \ 63275970Scy ((tvu) = (tstoushi[((tsf) >> 24) & 0xff] \ 64275970Scy + tstousmid[((tsf) >> 16) & 0xff] \ 65275970Scy + tstouslo[((tsf) >> 9) & 0x7f] \ 66275970Scy + TV_ROUNDBIT) >> TV_SHIFT) 67275970Scy#else 68275970Scy# define TSFTOTVU(tsf, tvu) \ 69275970Scy ((tvu) = (int32) \ 70275970Scy (((u_int64)(tsf) * MICROSECONDS + 0x80000000) >> 32)) 71275970Scy#endif 72275970Scy 73275970Scy/* 74275970Scy * Convert a struct timeval to a time stamp. 75275970Scy */ 76275970Scy#define TVTOTS(tv, ts) \ 77275970Scy do { \ 78275970Scy (ts)->l_ui = (u_long)(tv)->tv_sec; \ 79275970Scy TVUTOTSF((tv)->tv_usec, (ts)->l_uf); \ 80275970Scy } while (FALSE) 81275970Scy 82275970Scy#define sTVTOTS(tv, ts) \ 83275970Scy do { \ 84275970Scy int isneg = 0; \ 85275970Scy long usec; \ 86275970Scy (ts)->l_ui = (tv)->tv_sec; \ 87275970Scy usec = (tv)->tv_usec; \ 88275970Scy if (((tv)->tv_sec < 0) || ((tv)->tv_usec < 0)) { \ 89275970Scy usec = -usec; \ 90275970Scy (ts)->l_ui = -(ts)->l_ui; \ 91275970Scy isneg = 1; \ 92275970Scy } \ 93275970Scy TVUTOTSF(usec, (ts)->l_uf); \ 94275970Scy if (isneg) { \ 95275970Scy L_NEG((ts)); \ 96275970Scy } \ 97275970Scy } while (FALSE) 98275970Scy 99275970Scy/* 100275970Scy * Convert a time stamp to a struct timeval. The time stamp 101275970Scy * has to be positive. 102275970Scy */ 103275970Scy#define TSTOTV(ts, tv) \ 104275970Scy do { \ 105275970Scy (tv)->tv_sec = (ts)->l_ui; \ 106275970Scy TSFTOTVU((ts)->l_uf, (tv)->tv_usec); \ 107275970Scy if ((tv)->tv_usec == 1000000) { \ 108275970Scy (tv)->tv_sec++; \ 109275970Scy (tv)->tv_usec = 0; \ 110275970Scy } \ 111275970Scy } while (FALSE) 112275970Scy 113275970Scy 114275970Scy/* 115275970Scy * predicate: returns TRUE if the microseconds are in nominal range 116275970Scy * use like: int timeval_isnormal(const struct timeval *x) 117275970Scy */ 118275970Scy#define timeval_isnormal(x) \ 119275970Scy ((x)->tv_usec >= 0 && (x)->tv_usec < MICROSECONDS) 120275970Scy 121275970Scy/* 122275970Scy * Convert milliseconds to a time stamp fraction. Unused except for 123275970Scy * refclock_leitch.c, so accompanying lookup tables were removed in 124275970Scy * favor of reusing the microseconds conversion tables. 125275970Scy */ 126275970Scy#define MSUTOTSF(msu, tsf) TVUTOTSF((msu) * 1000, tsf) 127275970Scy 128275970Scy/* 129275970Scy * predicate: returns TRUE if the microseconds are out-of-bounds 130275970Scy * use like: int timeval_isdenormal(const struct timeval *x) 131275970Scy */ 132275970Scy#define timeval_isdenormal(x) (!timeval_isnormal(x)) 133275970Scy 134275970Scy/* make sure microseconds are in nominal range */ 135275970Scystatic inline struct timeval 136275970Scynormalize_tval( 137275970Scy struct timeval x 138275970Scy ) 139275970Scy{ 140275970Scy long z; 141275970Scy 142275970Scy /* 143275970Scy * If the fraction becomes excessive denormal, we use division 144275970Scy * to do first partial normalisation. The normalisation loops 145275970Scy * following will do the remaining cleanup. Since the size of 146275970Scy * tv_usec has a peculiar definition by the standard the range 147275970Scy * check is coded manually. And labs() is intentionally not used 148275970Scy * here: it has implementation-defined behaviour when applied 149275970Scy * to LONG_MIN. 150275970Scy */ 151275970Scy if (x.tv_usec < -3l * MICROSECONDS || 152275970Scy x.tv_usec > 3l * MICROSECONDS ) { 153275970Scy z = x.tv_usec / MICROSECONDS; 154275970Scy x.tv_usec -= z * MICROSECONDS; 155275970Scy x.tv_sec += z; 156275970Scy } 157275970Scy 158275970Scy /* 159275970Scy * Do any remaining normalisation steps in loops. This takes 3 160275970Scy * steps max, and should outperform a division even if the 161275970Scy * mul-by-inverse trick is employed. (It also does the floor 162275970Scy * division adjustment if the above division was executed.) 163275970Scy */ 164275970Scy if (x.tv_usec < 0) 165275970Scy do { 166275970Scy x.tv_usec += MICROSECONDS; 167275970Scy x.tv_sec--; 168275970Scy } while (x.tv_usec < 0); 169275970Scy else if (x.tv_usec >= MICROSECONDS) 170275970Scy do { 171275970Scy x.tv_usec -= MICROSECONDS; 172275970Scy x.tv_sec++; 173275970Scy } while (x.tv_usec >= MICROSECONDS); 174275970Scy 175275970Scy return x; 176275970Scy} 177275970Scy 178275970Scy/* x = a + b */ 179275970Scystatic inline struct timeval 180275970Scyadd_tval( 181275970Scy struct timeval a, 182275970Scy struct timeval b 183275970Scy ) 184275970Scy{ 185275970Scy struct timeval x; 186275970Scy 187275970Scy x = a; 188275970Scy x.tv_sec += b.tv_sec; 189275970Scy x.tv_usec += b.tv_usec; 190275970Scy 191275970Scy return normalize_tval(x); 192275970Scy} 193275970Scy 194275970Scy/* x = a + b, b is fraction only */ 195275970Scystatic inline struct timeval 196275970Scyadd_tval_us( 197275970Scy struct timeval a, 198275970Scy long b 199275970Scy ) 200275970Scy{ 201275970Scy struct timeval x; 202275970Scy 203275970Scy x = a; 204275970Scy x.tv_usec += b; 205275970Scy 206275970Scy return normalize_tval(x); 207275970Scy} 208275970Scy 209275970Scy/* x = a - b */ 210275970Scystatic inline struct timeval 211275970Scysub_tval( 212275970Scy struct timeval a, 213275970Scy struct timeval b 214275970Scy ) 215275970Scy{ 216275970Scy struct timeval x; 217275970Scy 218275970Scy x = a; 219275970Scy x.tv_sec -= b.tv_sec; 220275970Scy x.tv_usec -= b.tv_usec; 221275970Scy 222275970Scy return normalize_tval(x); 223275970Scy} 224275970Scy 225275970Scy/* x = a - b, b is fraction only */ 226275970Scystatic inline struct timeval 227275970Scysub_tval_us( 228275970Scy struct timeval a, 229275970Scy long b 230275970Scy ) 231275970Scy{ 232275970Scy struct timeval x; 233275970Scy 234275970Scy x = a; 235275970Scy x.tv_usec -= b; 236275970Scy 237275970Scy return normalize_tval(x); 238275970Scy} 239275970Scy 240275970Scy/* x = -a */ 241275970Scystatic inline struct timeval 242275970Scyneg_tval( 243275970Scy struct timeval a 244275970Scy ) 245275970Scy{ 246275970Scy struct timeval x; 247275970Scy 248275970Scy x.tv_sec = -a.tv_sec; 249275970Scy x.tv_usec = -a.tv_usec; 250275970Scy 251275970Scy return normalize_tval(x); 252275970Scy} 253275970Scy 254275970Scy/* x = abs(a) */ 255275970Scystatic inline struct timeval 256275970Scyabs_tval( 257275970Scy struct timeval a 258275970Scy ) 259275970Scy{ 260275970Scy struct timeval c; 261275970Scy 262275970Scy c = normalize_tval(a); 263275970Scy if (c.tv_sec < 0) { 264275970Scy if (c.tv_usec != 0) { 265275970Scy c.tv_sec = -c.tv_sec - 1; 266275970Scy c.tv_usec = MICROSECONDS - c.tv_usec; 267275970Scy } else { 268275970Scy c.tv_sec = -c.tv_sec; 269275970Scy } 270275970Scy } 271275970Scy 272275970Scy return c; 273275970Scy} 274275970Scy 275275970Scy/* 276275970Scy * compare previously-normalised a and b 277275970Scy * return 1 / 0 / -1 if a < / == / > b 278275970Scy */ 279275970Scystatic inline int 280275970Scycmp_tval( 281275970Scy struct timeval a, 282275970Scy struct timeval b 283275970Scy ) 284275970Scy{ 285275970Scy int r; 286275970Scy 287275970Scy r = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec); 288275970Scy if (0 == r) 289275970Scy r = (a.tv_usec > b.tv_usec) - 290275970Scy (a.tv_usec < b.tv_usec); 291275970Scy 292275970Scy return r; 293275970Scy} 294275970Scy 295275970Scy/* 296275970Scy * compare possibly-denormal a and b 297275970Scy * return 1 / 0 / -1 if a < / == / > b 298275970Scy */ 299275970Scystatic inline int 300275970Scycmp_tval_denorm( 301275970Scy struct timeval a, 302275970Scy struct timeval b 303275970Scy ) 304275970Scy{ 305275970Scy return cmp_tval(normalize_tval(a), normalize_tval(b)); 306275970Scy} 307275970Scy 308275970Scy/* 309275970Scy * test previously-normalised a 310275970Scy * return 1 / 0 / -1 if a < / == / > 0 311275970Scy */ 312275970Scystatic inline int 313275970Scytest_tval( 314275970Scy struct timeval a 315275970Scy ) 316275970Scy{ 317275970Scy int r; 318275970Scy 319275970Scy r = (a.tv_sec > 0) - (a.tv_sec < 0); 320275970Scy if (r == 0) 321275970Scy r = (a.tv_usec > 0); 322275970Scy 323275970Scy return r; 324275970Scy} 325275970Scy 326275970Scy/* 327275970Scy * test possibly-denormal a 328275970Scy * return 1 / 0 / -1 if a < / == / > 0 329275970Scy */ 330275970Scystatic inline int 331275970Scytest_tval_denorm( 332275970Scy struct timeval a 333275970Scy ) 334275970Scy{ 335275970Scy return test_tval(normalize_tval(a)); 336275970Scy} 337275970Scy 338275970Scy/* return LIB buffer ptr to string rep */ 339275970Scystatic inline const char * 340275970Scytvaltoa( 341275970Scy struct timeval x 342275970Scy ) 343275970Scy{ 344275970Scy return format_time_fraction(x.tv_sec, x.tv_usec, 6); 345275970Scy} 346275970Scy 347275970Scy/* convert from timeval duration to l_fp duration */ 348275970Scystatic inline l_fp 349275970Scytval_intv_to_lfp( 350275970Scy struct timeval x 351275970Scy ) 352275970Scy{ 353275970Scy struct timeval v; 354275970Scy l_fp y; 355275970Scy 356275970Scy v = normalize_tval(x); 357275970Scy TVUTOTSF(v.tv_usec, y.l_uf); 358275970Scy y.l_i = (int32)v.tv_sec; 359275970Scy 360275970Scy return y; 361275970Scy} 362275970Scy 363275970Scy/* x must be UN*X epoch, output *y will be in NTP epoch */ 364275970Scystatic inline l_fp 365275970Scytval_stamp_to_lfp( 366275970Scy struct timeval x 367275970Scy ) 368275970Scy{ 369275970Scy l_fp y; 370275970Scy 371275970Scy y = tval_intv_to_lfp(x); 372275970Scy y.l_ui += JAN_1970; 373275970Scy 374275970Scy return y; 375275970Scy} 376275970Scy 377275970Scy/* convert to l_fp type, relative signed/unsigned and absolute */ 378275970Scystatic inline struct timeval 379275970Scylfp_intv_to_tval( 380275970Scy l_fp x 381275970Scy ) 382275970Scy{ 383275970Scy struct timeval out; 384275970Scy l_fp absx; 385275970Scy int neg; 386275970Scy 387275970Scy neg = L_ISNEG(&x); 388275970Scy absx = x; 389275970Scy if (neg) { 390275970Scy L_NEG(&absx); 391275970Scy } 392275970Scy TSFTOTVU(absx.l_uf, out.tv_usec); 393275970Scy out.tv_sec = absx.l_i; 394275970Scy if (neg) { 395275970Scy out.tv_sec = -out.tv_sec; 396275970Scy out.tv_usec = -out.tv_usec; 397275970Scy out = normalize_tval(out); 398275970Scy } 399275970Scy 400275970Scy return out; 401275970Scy} 402275970Scy 403275970Scystatic inline struct timeval 404275970Scylfp_uintv_to_tval( 405275970Scy l_fp x 406275970Scy ) 407275970Scy{ 408275970Scy struct timeval out; 409275970Scy 410275970Scy TSFTOTVU(x.l_uf, out.tv_usec); 411275970Scy out.tv_sec = x.l_ui; 412275970Scy 413275970Scy return out; 414275970Scy} 415275970Scy 416275970Scy/* 417275970Scy * absolute (timestamp) conversion. Input is time in NTP epoch, output 418275970Scy * is in UN*X epoch. The NTP time stamp will be expanded around the 419275970Scy * pivot time *p or the current time, if p is NULL. 420275970Scy */ 421275970Scystatic inline struct timeval 422275970Scylfp_stamp_to_tval( 423275970Scy l_fp x, 424275970Scy const time_t * p 425275970Scy ) 426275970Scy{ 427275970Scy struct timeval out; 428275970Scy vint64 sec; 429275970Scy 430275970Scy sec = ntpcal_ntp_to_time(x.l_ui, p); 431275970Scy TSFTOTVU(x.l_uf, out.tv_usec); 432275970Scy 433275970Scy /* copying a vint64 to a time_t needs some care... */ 434275970Scy#if SIZEOF_TIME_T <= 4 435275970Scy out.tv_sec = (time_t)sec.d_s.lo; 436275970Scy#elif defined(HAVE_INT64) 437275970Scy out.tv_sec = (time_t)sec.q_s; 438275970Scy#else 439275970Scy out.tv_sec = ((time_t)sec.d_s.hi << 32) | sec.d_s.lo; 440275970Scy#endif 441275970Scy out = normalize_tval(out); 442275970Scy 443275970Scy return out; 444275970Scy} 445275970Scy 446275970Scy#endif /* TIMEVALOPS_H */ 447