timevalops.h revision 290000
145135Sobrien/* 258478Sobrien * timevalops.h -- calculations on 'struct timeval' values 345135Sobrien * 445135Sobrien * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project. 545135Sobrien * The contents of 'html/copyright.html' apply. 645135Sobrien * 745135Sobrien * For a rationale look at 'timespecops.h'; we do the same here, but the 845135Sobrien * normalisation keeps the microseconds in [0 .. 10^6[, of course. 945135Sobrien */ 1045135Sobrien#ifndef TIMEVALOPS_H 1145135Sobrien#define TIMEVALOPS_H 1245135Sobrien 1345135Sobrien#include <sys/types.h> 1445135Sobrien#include <stdio.h> 1545135Sobrien 1645135Sobrien#include "ntp.h" 1745135Sobrien#include "timetoa.h" 1845135Sobrien 1945135Sobrien 2045135Sobrien/* microseconds per second */ 2145135Sobrien#define MICROSECONDS 1000000 2245135Sobrien 2345135Sobrien#ifndef HAVE_U_INT64 2458478Sobrien# define USE_TSF_USEC_TABLES 2558478Sobrien#endif 2645135Sobrien 2745135Sobrien/* 2852113Sobrien * Convert usec to a time stamp fraction. 2945135Sobrien */ 3052113Sobrien#ifdef USE_TSF_USEC_TABLES 3158478Sobrienextern const u_int32 ustotslo[]; 3245135Sobrienextern const u_int32 ustotsmid[]; 3346122Sobrienextern const u_int32 ustotshi[]; 3445135Sobrien 3573243Sobrien# define TVUTOTSF(tvu, tsf) \ 3648474Sobrien ((tsf) = ustotslo[(tvu) & 0xff] \ 3745135Sobrien + ustotsmid[((tvu) >> 8) & 0xff] \ 3845940Sobrien + ustotshi[((tvu) >> 16) & 0xf]) 3946122Sobrien#else 4045135Sobrien# define TVUTOTSF(tvu, tsf) \ 4145135Sobrien ((tsf) = (u_int32) \ 4245135Sobrien ((((u_int64)(tvu) << 32) + MICROSECONDS / 2) / \ 4345135Sobrien MICROSECONDS)) 4458478Sobrien#endif 4558478Sobrien 4649854Sobrien/* 4758478Sobrien * Convert a time stamp fraction to microseconds. The time stamp 4858478Sobrien * fraction is assumed to be unsigned. 4945940Sobrien */ 5045135Sobrien#ifdef USE_TSF_USEC_TABLES 5150080Sobrienextern const u_int32 tstouslo[256]; 5250080Sobrienextern const u_int32 tstousmid[256]; 5350080Sobrienextern const u_int32 tstoushi[128]; 5445135Sobrien 5558478Sobrien/* 5658478Sobrien * TV_SHIFT is used to turn the table result into a usec value. To 5749854Sobrien * round, add in TV_ROUNDBIT before shifting. 5845317Sobrien */ 5945317Sobrien#define TV_SHIFT 3 6072151Sobrien#define TV_ROUNDBIT 0x4 6145135Sobrien 6273243Sobrien# define TSFTOTVU(tsf, tvu) \ 6373243Sobrien ((tvu) = (tstoushi[((tsf) >> 24) & 0xff] \ 6473243Sobrien + tstousmid[((tsf) >> 16) & 0xff] \ 6573243Sobrien + tstouslo[((tsf) >> 9) & 0x7f] \ 6673243Sobrien + TV_ROUNDBIT) >> TV_SHIFT) 6773243Sobrien#else 6854807Sobrien# define TSFTOTVU(tsf, tvu) \ 6954807Sobrien ((tvu) = (int32) \ 7058478Sobrien (((u_int64)(tsf) * MICROSECONDS + 0x80000000) >> 32)) 7154807Sobrien#endif 7254807Sobrien 7345458Sobrien/* 7471646Sjdp * Convert a struct timeval to a time stamp. 7571646Sjdp */ 7648474Sobrien#define TVTOTS(tv, ts) \ 7758478Sobrien do { \ 7873243Sobrien (ts)->l_ui = (u_long)(tv)->tv_sec; \ 7973243Sobrien TVUTOTSF((tv)->tv_usec, (ts)->l_uf); \ 8073243Sobrien } while (FALSE) 8173243Sobrien 8268452Sobrien#define sTVTOTS(tv, ts) \ 8345135Sobrien do { \ 8445458Sobrien int isneg = 0; \ 8558478Sobrien long usec; \ 8658478Sobrien (ts)->l_ui = (tv)->tv_sec; \ 8758478Sobrien usec = (tv)->tv_usec; \ 8858478Sobrien if (((tv)->tv_sec < 0) || ((tv)->tv_usec < 0)) { \ 8958478Sobrien usec = -usec; \ 9058478Sobrien (ts)->l_ui = -(ts)->l_ui; \ 9158478Sobrien isneg = 1; \ 9258478Sobrien } \ 9358478Sobrien TVUTOTSF(usec, (ts)->l_uf); \ 9458478Sobrien if (isneg) { \ 9558478Sobrien L_NEG((ts)); \ 9658478Sobrien } \ 9758478Sobrien } while (FALSE) 9858478Sobrien 9958478Sobrien/* 10058478Sobrien * Convert a time stamp to a struct timeval. The time stamp 10158478Sobrien * has to be positive. 10258478Sobrien */ 10358478Sobrien#define TSTOTV(ts, tv) \ 10458478Sobrien do { \ 10558478Sobrien (tv)->tv_sec = (ts)->l_ui; \ 10645135Sobrien TSFTOTVU((ts)->l_uf, (tv)->tv_usec); \ 10745135Sobrien if ((tv)->tv_usec == 1000000) { \ 10845135Sobrien (tv)->tv_sec++; \ 10948475Sobrien (tv)->tv_usec = 0; \ 11073243Sobrien } \ 11148474Sobrien } while (FALSE) 11258478Sobrien 11345135Sobrien 11445135Sobrien/* 11558478Sobrien * predicate: returns TRUE if the microseconds are in nominal range 11658478Sobrien * use like: int timeval_isnormal(const struct timeval *x) 11758478Sobrien */ 11858478Sobrien#define timeval_isnormal(x) \ 11958478Sobrien ((x)->tv_usec >= 0 && (x)->tv_usec < MICROSECONDS) 12058478Sobrien 12158478Sobrien/* 12258478Sobrien * Convert milliseconds to a time stamp fraction. Unused except for 12345135Sobrien * refclock_leitch.c, so accompanying lookup tables were removed in 12445135Sobrien * favor of reusing the microseconds conversion tables. 12558478Sobrien */ 12658478Sobrien#define MSUTOTSF(msu, tsf) TVUTOTSF((msu) * 1000, tsf) 12758478Sobrien 12858478Sobrien/* 12958478Sobrien * predicate: returns TRUE if the microseconds are out-of-bounds 13058478Sobrien * use like: int timeval_isdenormal(const struct timeval *x) 13158478Sobrien */ 13258478Sobrien#define timeval_isdenormal(x) (!timeval_isnormal(x)) 13358478Sobrien 13458478Sobrien/* make sure microseconds are in nominal range */ 13558478Sobrienstatic inline struct timeval 13660776Sobriennormalize_tval( 13760776Sobrien struct timeval x 13860776Sobrien ) 13960776Sobrien{ 14060776Sobrien long z; 14160776Sobrien 14256576Sobrien /* 14356576Sobrien * If the fraction becomes excessive denormal, we use division 14456576Sobrien * to do first partial normalisation. The normalisation loops 14545277Sobrien * following will do the remaining cleanup. Since the size of 14645135Sobrien * tv_usec has a peculiar definition by the standard the range 14758478Sobrien * check is coded manually. And labs() is intentionally not used 14858478Sobrien * here: it has implementation-defined behaviour when applied 14958478Sobrien * to LONG_MIN. 15058478Sobrien */ 15158478Sobrien if (x.tv_usec < -3l * MICROSECONDS || 15258478Sobrien x.tv_usec > 3l * MICROSECONDS ) { 15358478Sobrien z = x.tv_usec / MICROSECONDS; 15458478Sobrien x.tv_usec -= z * MICROSECONDS; 15558478Sobrien x.tv_sec += z; 15673243Sobrien } 15758478Sobrien 15858478Sobrien /* 15958478Sobrien * Do any remaining normalisation steps in loops. This takes 3 16073243Sobrien * steps max, and should outperform a division even if the 16158478Sobrien * mul-by-inverse trick is employed. (It also does the floor 16258478Sobrien * division adjustment if the above division was executed.) 16358478Sobrien */ 16458478Sobrien if (x.tv_usec < 0) 16558478Sobrien do { 16673243Sobrien x.tv_usec += MICROSECONDS; 16758478Sobrien x.tv_sec--; 16858478Sobrien } while (x.tv_usec < 0); 16958478Sobrien else if (x.tv_usec >= MICROSECONDS) 17058478Sobrien do { 17158478Sobrien x.tv_usec -= MICROSECONDS; 17258478Sobrien x.tv_sec++; 17358478Sobrien } while (x.tv_usec >= MICROSECONDS); 17458478Sobrien 17558478Sobrien return x; 17658478Sobrien} 17758478Sobrien 17858478Sobrien/* x = a + b */ 17958478Sobrienstatic inline struct timeval 18058478Sobrienadd_tval( 18158478Sobrien struct timeval a, 18258478Sobrien struct timeval b 18373243Sobrien ) 18458478Sobrien{ 18558478Sobrien struct timeval x; 18658478Sobrien 18758478Sobrien x = a; 18858478Sobrien x.tv_sec += b.tv_sec; 18973243Sobrien x.tv_usec += b.tv_usec; 19058478Sobrien 19158478Sobrien return normalize_tval(x); 19273243Sobrien} 19358478Sobrien 19458478Sobrien/* x = a + b, b is fraction only */ 19573243Sobrienstatic inline struct timeval 19658478Sobrienadd_tval_us( 19758478Sobrien struct timeval a, 19858478Sobrien long b 19958478Sobrien ) 20058478Sobrien{ 20173243Sobrien struct timeval x; 20258478Sobrien 20358478Sobrien x = a; 20458478Sobrien x.tv_usec += b; 20558478Sobrien 20658478Sobrien return normalize_tval(x); 20758478Sobrien} 20858478Sobrien 20958478Sobrien/* x = a - b */ 21073243Sobrienstatic inline struct timeval 21158478Sobriensub_tval( 21258478Sobrien struct timeval a, 21358478Sobrien struct timeval b 21473243Sobrien ) 21558478Sobrien{ 21658478Sobrien struct timeval x; 21758478Sobrien 21858478Sobrien x = a; 21958478Sobrien x.tv_sec -= b.tv_sec; 22058478Sobrien x.tv_usec -= b.tv_usec; 22158478Sobrien 22258478Sobrien return normalize_tval(x); 22358478Sobrien} 22458478Sobrien 22558478Sobrien/* x = a - b, b is fraction only */ 22658478Sobrienstatic inline struct timeval 22758478Sobriensub_tval_us( 22873243Sobrien struct timeval a, 22958478Sobrien long b 23058478Sobrien ) 23158478Sobrien{ 23258478Sobrien struct timeval x; 23358478Sobrien 23458478Sobrien x = a; 23558478Sobrien x.tv_usec -= b; 23658478Sobrien 23758478Sobrien return normalize_tval(x); 23858478Sobrien} 23958478Sobrien 24058478Sobrien/* x = -a */ 24158478Sobrienstatic inline struct timeval 24273243Sobrienneg_tval( 24358478Sobrien struct timeval a 24458478Sobrien ) 24573243Sobrien{ 24658478Sobrien struct timeval x; 24758478Sobrien 24858478Sobrien x.tv_sec = -a.tv_sec; 24958478Sobrien x.tv_usec = -a.tv_usec; 25058478Sobrien 25158478Sobrien return normalize_tval(x); 25258478Sobrien} 25358478Sobrien 25458478Sobrien/* x = abs(a) */ 25558478Sobrienstatic inline struct timeval 25658478Sobrienabs_tval( 25758478Sobrien struct timeval a 25873243Sobrien ) 25958478Sobrien{ 26058478Sobrien struct timeval c; 26158478Sobrien 26273243Sobrien c = normalize_tval(a); 26358478Sobrien if (c.tv_sec < 0) { 26458478Sobrien if (c.tv_usec != 0) { 26558478Sobrien c.tv_sec = -c.tv_sec - 1; 26658478Sobrien c.tv_usec = MICROSECONDS - c.tv_usec; 26758478Sobrien } else { 26858478Sobrien c.tv_sec = -c.tv_sec; 26973243Sobrien } 27058478Sobrien } 27158478Sobrien 27258478Sobrien return c; 27358478Sobrien} 27458478Sobrien 27558478Sobrien/* 27658478Sobrien * compare previously-normalised a and b 27773243Sobrien * return 1 / 0 / -1 if a < / == / > b 27858478Sobrien */ 27958478Sobrienstatic inline int 28058478Sobriencmp_tval( 28158478Sobrien struct timeval a, 28258478Sobrien struct timeval b 28373243Sobrien ) 28473243Sobrien{ 28558478Sobrien int r; 28658478Sobrien 28758478Sobrien r = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec); 28858478Sobrien if (0 == r) 28958478Sobrien r = (a.tv_usec > b.tv_usec) - 29058478Sobrien (a.tv_usec < b.tv_usec); 29158478Sobrien 29258478Sobrien return r; 29358478Sobrien} 29458478Sobrien 29573243Sobrien/* 29658478Sobrien * compare possibly-denormal a and b 29758478Sobrien * return 1 / 0 / -1 if a < / == / > b 29858478Sobrien */ 29958478Sobrienstatic inline int 30058478Sobriencmp_tval_denorm( 30158478Sobrien struct timeval a, 30258478Sobrien struct timeval b 30358478Sobrien ) 30458478Sobrien{ 30558478Sobrien return cmp_tval(normalize_tval(a), normalize_tval(b)); 30658478Sobrien} 30773243Sobrien 30858478Sobrien/* 30958478Sobrien * test previously-normalised a 31058478Sobrien * return 1 / 0 / -1 if a < / == / > 0 31158478Sobrien */ 31258478Sobrienstatic inline int 31358478Sobrientest_tval( 31458478Sobrien struct timeval a 31558478Sobrien ) 31658478Sobrien{ 31758478Sobrien int r; 31858478Sobrien 31973243Sobrien r = (a.tv_sec > 0) - (a.tv_sec < 0); 32058478Sobrien if (r == 0) 32158478Sobrien r = (a.tv_usec > 0); 32258478Sobrien 32358478Sobrien return r; 32458478Sobrien} 32558478Sobrien 32658478Sobrien/* 32758478Sobrien * test possibly-denormal a 32858478Sobrien * return 1 / 0 / -1 if a < / == / > 0 32958478Sobrien */ 33058478Sobrienstatic inline int 33173243Sobrientest_tval_denorm( 33258478Sobrien struct timeval a 33358478Sobrien ) 33458478Sobrien{ 33558478Sobrien return test_tval(normalize_tval(a)); 33658478Sobrien} 33758478Sobrien 33858478Sobrien/* return LIB buffer ptr to string rep */ 33958478Sobrienstatic inline const char * 34058478Sobrientvaltoa( 34158478Sobrien struct timeval x 34258478Sobrien ) 34358478Sobrien{ 34458478Sobrien return format_time_fraction(x.tv_sec, x.tv_usec, 6); 34558478Sobrien} 34658478Sobrien 34758478Sobrien/* convert from timeval duration to l_fp duration */ 34858478Sobrienstatic inline l_fp 34958478Sobrientval_intv_to_lfp( 35058478Sobrien struct timeval x 35158478Sobrien ) 35258478Sobrien{ 35358478Sobrien struct timeval v; 35458478Sobrien l_fp y; 35558478Sobrien 35658478Sobrien v = normalize_tval(x); 35758478Sobrien TVUTOTSF(v.tv_usec, y.l_uf); 35858478Sobrien y.l_i = (int32)v.tv_sec; 35958478Sobrien 36058478Sobrien return y; 36158478Sobrien} 36258478Sobrien 36358478Sobrien/* x must be UN*X epoch, output *y will be in NTP epoch */ 36458478Sobrienstatic inline l_fp 36558478Sobrientval_stamp_to_lfp( 36658478Sobrien struct timeval x 36758478Sobrien ) 36858478Sobrien{ 36958478Sobrien l_fp y; 37073243Sobrien 37158478Sobrien y = tval_intv_to_lfp(x); 37258478Sobrien y.l_ui += JAN_1970; 37358478Sobrien 37458478Sobrien return y; 37558478Sobrien} 37658478Sobrien 37758478Sobrien/* convert to l_fp type, relative signed/unsigned and absolute */ 37858478Sobrienstatic inline struct timeval 37958478Sobrienlfp_intv_to_tval( 38058478Sobrien l_fp x 38158478Sobrien ) 38258478Sobrien{ 38358478Sobrien struct timeval out; 38458478Sobrien l_fp absx; 38558478Sobrien int neg; 38658478Sobrien 38758478Sobrien neg = L_ISNEG(&x); 38873243Sobrien absx = x; 38958478Sobrien if (neg) { 39073243Sobrien L_NEG(&absx); 39158478Sobrien } 39273243Sobrien TSFTOTVU(absx.l_uf, out.tv_usec); 39358478Sobrien out.tv_sec = absx.l_i; 39458478Sobrien if (neg) { 39558478Sobrien out.tv_sec = -out.tv_sec; 39673243Sobrien out.tv_usec = -out.tv_usec; 39758478Sobrien out = normalize_tval(out); 39858478Sobrien } 39973243Sobrien 40058478Sobrien return out; 40173243Sobrien} 40258478Sobrien 40358478Sobrienstatic inline struct timeval 40458478Sobrienlfp_uintv_to_tval( 40558478Sobrien l_fp x 40658478Sobrien ) 40758478Sobrien{ 40858478Sobrien struct timeval out; 40958478Sobrien 41058478Sobrien TSFTOTVU(x.l_uf, out.tv_usec); 41158478Sobrien out.tv_sec = x.l_ui; 41258478Sobrien 41358478Sobrien return out; 41458478Sobrien} 41558478Sobrien 41658478Sobrien/* 41758478Sobrien * absolute (timestamp) conversion. Input is time in NTP epoch, output 41858478Sobrien * is in UN*X epoch. The NTP time stamp will be expanded around the 41958478Sobrien * pivot time *p or the current time, if p is NULL. 42058478Sobrien */ 42158478Sobrienstatic inline struct timeval 42258478Sobrienlfp_stamp_to_tval( 42358478Sobrien l_fp x, 42458478Sobrien const time_t * p 42558478Sobrien ) 42658478Sobrien{ 42758478Sobrien struct timeval out; 42858478Sobrien vint64 sec; 42958478Sobrien 43058478Sobrien sec = ntpcal_ntp_to_time(x.l_ui, p); 43158478Sobrien TSFTOTVU(x.l_uf, out.tv_usec); 43258478Sobrien 43358478Sobrien /* copying a vint64 to a time_t needs some care... */ 43458478Sobrien#if SIZEOF_TIME_T <= 4 43558478Sobrien out.tv_sec = (time_t)sec.d_s.lo; 43658478Sobrien#elif defined(HAVE_INT64) 43758478Sobrien out.tv_sec = (time_t)sec.q_s; 43858478Sobrien#else 43958478Sobrien out.tv_sec = ((time_t)sec.d_s.hi << 32) | sec.d_s.lo; 44058478Sobrien#endif 44158478Sobrien out = normalize_tval(out); 44258478Sobrien 44358478Sobrien return out; 44458478Sobrien} 44558478Sobrien 44658478Sobrien#endif /* TIMEVALOPS_H */ 44758478Sobrien