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