Home | History | Annotate | Line # | Download | only in include
      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