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