xref: /freebsd/contrib/ntp/include/timespecops.h (revision e43d33d286a1aa41b6fc6a209f28a18e8cd7437a)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * timespecops.h -- calculations on 'struct timespec' values
32b15cb3dSCy Schubert  *
42b15cb3dSCy Schubert  * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
52b15cb3dSCy Schubert  * The contents of 'html/copyright.html' apply.
62b15cb3dSCy Schubert  *
72b15cb3dSCy Schubert  * Rationale
82b15cb3dSCy Schubert  * ---------
92b15cb3dSCy Schubert  *
102b15cb3dSCy Schubert  * Doing basic arithmetic on a 'struct timespec' is not exceedingly
112b15cb3dSCy Schubert  * hard, but it requires tedious and repetitive code to keep the result
122b15cb3dSCy Schubert  * normalised. We consider a timespec normalised when the nanosecond
132b15cb3dSCy Schubert  * fraction is in the interval [0 .. 10^9[ ; there are multiple value
142b15cb3dSCy Schubert  * pairs of seconds and nanoseconds that denote the same time interval,
152b15cb3dSCy Schubert  * but the normalised representation is unique. No two different
162b15cb3dSCy Schubert  * intervals can have the same normalised representation.
172b15cb3dSCy Schubert  *
182b15cb3dSCy Schubert  * Another topic is the representation of negative time intervals.
192b15cb3dSCy Schubert  * There's more than one way to this, since both the seconds and the
202b15cb3dSCy Schubert  * nanoseconds of a timespec are signed values. IMHO, the easiest way is
212b15cb3dSCy Schubert  * to use a complement representation where the nanoseconds are still
222b15cb3dSCy Schubert  * normalised, no matter what the sign of the seconds value. This makes
232b15cb3dSCy Schubert  * normalisation easier, since the sign of the integer part is
242b15cb3dSCy Schubert  * irrelevant, and it removes several sign decision cases during the
252b15cb3dSCy Schubert  * calculations.
262b15cb3dSCy Schubert  *
272b15cb3dSCy Schubert  * As long as no signed integer overflow can occur with the nanosecond
282b15cb3dSCy Schubert  * part of the operands, all operations work as expected and produce a
292b15cb3dSCy Schubert  * normalised result.
302b15cb3dSCy Schubert  *
312b15cb3dSCy Schubert  * The exception to this are functions fix a '_fast' suffix, which do no
322b15cb3dSCy Schubert  * normalisation on input data and therefore expect the input data to be
332b15cb3dSCy Schubert  * normalised.
342b15cb3dSCy Schubert  *
352b15cb3dSCy Schubert  * Input and output operands may overlap; all input is consumed before
362b15cb3dSCy Schubert  * the output is written to.
372b15cb3dSCy Schubert  */
382b15cb3dSCy Schubert #ifndef TIMESPECOPS_H
392b15cb3dSCy Schubert #define TIMESPECOPS_H
402b15cb3dSCy Schubert 
412b15cb3dSCy Schubert #include <sys/types.h>
422b15cb3dSCy Schubert #include <stdio.h>
432b15cb3dSCy Schubert #include <math.h>
442b15cb3dSCy Schubert 
452b15cb3dSCy Schubert #include "ntp.h"
462b15cb3dSCy Schubert #include "timetoa.h"
472b15cb3dSCy Schubert 
482b15cb3dSCy Schubert 
492b15cb3dSCy Schubert /* nanoseconds per second */
502b15cb3dSCy Schubert #define NANOSECONDS 1000000000
512b15cb3dSCy Schubert 
522b15cb3dSCy Schubert /* predicate: returns TRUE if the nanoseconds are in nominal range */
532b15cb3dSCy Schubert #define timespec_isnormal(x) \
542b15cb3dSCy Schubert 	((x)->tv_nsec >= 0 && (x)->tv_nsec < NANOSECONDS)
552b15cb3dSCy Schubert 
562b15cb3dSCy Schubert /* predicate: returns TRUE if the nanoseconds are out-of-bounds */
572b15cb3dSCy Schubert #define timespec_isdenormal(x)	(!timespec_isnormal(x))
582b15cb3dSCy Schubert 
592b15cb3dSCy Schubert 
602b15cb3dSCy Schubert 
612b15cb3dSCy Schubert 
622b15cb3dSCy Schubert /* make sure nanoseconds are in nominal range */
63*2d4e511cSCy Schubert extern struct timespec normalize_tspec(struct timespec x);
642b15cb3dSCy Schubert 
652b15cb3dSCy Schubert /* x = a + b */
662b15cb3dSCy Schubert static inline struct timespec
add_tspec(struct timespec a,struct timespec b)672b15cb3dSCy Schubert add_tspec(
682b15cb3dSCy Schubert 	struct timespec	a,
692b15cb3dSCy Schubert 	struct timespec	b
702b15cb3dSCy Schubert 	)
712b15cb3dSCy Schubert {
722b15cb3dSCy Schubert 	struct timespec	x;
732b15cb3dSCy Schubert 
742b15cb3dSCy Schubert 	x = a;
752b15cb3dSCy Schubert 	x.tv_sec += b.tv_sec;
762b15cb3dSCy Schubert 	x.tv_nsec += b.tv_nsec;
772b15cb3dSCy Schubert 
782b15cb3dSCy Schubert 	return normalize_tspec(x);
792b15cb3dSCy Schubert }
802b15cb3dSCy Schubert 
812b15cb3dSCy Schubert /* x = a + b, b is fraction only */
822b15cb3dSCy Schubert static inline struct timespec
add_tspec_ns(struct timespec a,long b)832b15cb3dSCy Schubert add_tspec_ns(
842b15cb3dSCy Schubert 	struct timespec	a,
852b15cb3dSCy Schubert 	long		b
862b15cb3dSCy Schubert 	)
872b15cb3dSCy Schubert {
882b15cb3dSCy Schubert 	struct timespec x;
892b15cb3dSCy Schubert 
902b15cb3dSCy Schubert 	x = a;
912b15cb3dSCy Schubert 	x.tv_nsec += b;
922b15cb3dSCy Schubert 
932b15cb3dSCy Schubert 	return normalize_tspec(x);
942b15cb3dSCy Schubert }
952b15cb3dSCy Schubert 
962b15cb3dSCy Schubert /* x = a - b */
972b15cb3dSCy Schubert static inline struct timespec
sub_tspec(struct timespec a,struct timespec b)982b15cb3dSCy Schubert sub_tspec(
992b15cb3dSCy Schubert 	struct timespec	a,
1002b15cb3dSCy Schubert 	struct timespec	b
1012b15cb3dSCy Schubert 	)
1022b15cb3dSCy Schubert {
1032b15cb3dSCy Schubert 	struct timespec x;
1042b15cb3dSCy Schubert 
1052b15cb3dSCy Schubert 	x = a;
1062b15cb3dSCy Schubert 	x.tv_sec -= b.tv_sec;
1072b15cb3dSCy Schubert 	x.tv_nsec -= b.tv_nsec;
1082b15cb3dSCy Schubert 
1092b15cb3dSCy Schubert 	return normalize_tspec(x);
1102b15cb3dSCy Schubert }
1112b15cb3dSCy Schubert 
1122b15cb3dSCy Schubert /* x = a - b, b is fraction only */
1132b15cb3dSCy Schubert static inline struct timespec
sub_tspec_ns(struct timespec a,long b)1142b15cb3dSCy Schubert sub_tspec_ns(
1152b15cb3dSCy Schubert 	struct timespec	a,
1162b15cb3dSCy Schubert 	long		b
1172b15cb3dSCy Schubert 	)
1182b15cb3dSCy Schubert {
1192b15cb3dSCy Schubert 	struct timespec	x;
1202b15cb3dSCy Schubert 
1212b15cb3dSCy Schubert 	x = a;
1222b15cb3dSCy Schubert 	x.tv_nsec -= b;
1232b15cb3dSCy Schubert 
1242b15cb3dSCy Schubert 	return normalize_tspec(x);
1252b15cb3dSCy Schubert }
1262b15cb3dSCy Schubert 
1272b15cb3dSCy Schubert /* x = -a */
1282b15cb3dSCy Schubert static inline struct timespec
neg_tspec(struct timespec a)1292b15cb3dSCy Schubert neg_tspec(
1302b15cb3dSCy Schubert 	struct timespec	a
1312b15cb3dSCy Schubert 	)
1322b15cb3dSCy Schubert {
1332b15cb3dSCy Schubert 	struct timespec	x;
1342b15cb3dSCy Schubert 
1352b15cb3dSCy Schubert 	x.tv_sec = -a.tv_sec;
1362b15cb3dSCy Schubert 	x.tv_nsec = -a.tv_nsec;
1372b15cb3dSCy Schubert 
1382b15cb3dSCy Schubert 	return normalize_tspec(x);
1392b15cb3dSCy Schubert }
1402b15cb3dSCy Schubert 
1412b15cb3dSCy Schubert /* x = abs(a) */
142*2d4e511cSCy Schubert struct timespec abs_tspec(struct timespec a);
1432b15cb3dSCy Schubert 
1442b15cb3dSCy Schubert /*
1452b15cb3dSCy Schubert  * compare previously-normalised a and b
1462b15cb3dSCy Schubert  * return 1 / 0 / -1 if a < / == / > b
1472b15cb3dSCy Schubert  */
148*2d4e511cSCy Schubert extern int cmp_tspec(struct timespec a,	struct timespec b);
1492b15cb3dSCy Schubert 
1502b15cb3dSCy Schubert /*
1512b15cb3dSCy Schubert  * compare possibly-denormal a and b
1522b15cb3dSCy Schubert  * return 1 / 0 / -1 if a < / == / > b
1532b15cb3dSCy Schubert  */
1542b15cb3dSCy Schubert static inline int
cmp_tspec_denorm(struct timespec a,struct timespec b)1552b15cb3dSCy Schubert cmp_tspec_denorm(
1562b15cb3dSCy Schubert 	struct timespec	a,
1572b15cb3dSCy Schubert 	struct timespec	b
1582b15cb3dSCy Schubert 	)
1592b15cb3dSCy Schubert {
1602b15cb3dSCy Schubert 	return cmp_tspec(normalize_tspec(a), normalize_tspec(b));
1612b15cb3dSCy Schubert }
1622b15cb3dSCy Schubert 
1632b15cb3dSCy Schubert /*
1642b15cb3dSCy Schubert  * test previously-normalised a
1652b15cb3dSCy Schubert  * return 1 / 0 / -1 if a < / == / > 0
1662b15cb3dSCy Schubert  */
167*2d4e511cSCy Schubert extern int test_tspec(struct timespec a);
1682b15cb3dSCy Schubert 
1692b15cb3dSCy Schubert /*
1702b15cb3dSCy Schubert  * test possibly-denormal a
1712b15cb3dSCy Schubert  * return 1 / 0 / -1 if a < / == / > 0
1722b15cb3dSCy Schubert  */
1732b15cb3dSCy Schubert static inline int
test_tspec_denorm(struct timespec a)1742b15cb3dSCy Schubert test_tspec_denorm(
1752b15cb3dSCy Schubert 	struct timespec	a
1762b15cb3dSCy Schubert 	)
1772b15cb3dSCy Schubert {
1782b15cb3dSCy Schubert 	return test_tspec(normalize_tspec(a));
1792b15cb3dSCy Schubert }
1802b15cb3dSCy Schubert 
1812b15cb3dSCy Schubert /* return LIB buffer ptr to string rep */
1822b15cb3dSCy Schubert static inline const char *
tspectoa(struct timespec x)1832b15cb3dSCy Schubert tspectoa(
1842b15cb3dSCy Schubert 	struct timespec	x
1852b15cb3dSCy Schubert 	)
1862b15cb3dSCy Schubert {
1872b15cb3dSCy Schubert 	return format_time_fraction(x.tv_sec, x.tv_nsec, 9);
1882b15cb3dSCy Schubert }
1892b15cb3dSCy Schubert 
1902b15cb3dSCy Schubert /*
1912b15cb3dSCy Schubert  *  convert to l_fp type, relative and absolute
1922b15cb3dSCy Schubert  */
1932b15cb3dSCy Schubert 
1942b15cb3dSCy Schubert /* convert from timespec duration to l_fp duration */
195*2d4e511cSCy Schubert extern l_fp tspec_intv_to_lfp(struct timespec x);
1962b15cb3dSCy Schubert 
1972b15cb3dSCy Schubert /* x must be UN*X epoch, output will be in NTP epoch */
1982b15cb3dSCy Schubert static inline l_fp
tspec_stamp_to_lfp(struct timespec x)1992b15cb3dSCy Schubert tspec_stamp_to_lfp(
2002b15cb3dSCy Schubert 	struct timespec	x
2012b15cb3dSCy Schubert 	)
2022b15cb3dSCy Schubert {
2032b15cb3dSCy Schubert 	l_fp		y;
2042b15cb3dSCy Schubert 
2052b15cb3dSCy Schubert 	y = tspec_intv_to_lfp(x);
2062b15cb3dSCy Schubert 	y.l_ui += JAN_1970;
2072b15cb3dSCy Schubert 
2082b15cb3dSCy Schubert 	return y;
2092b15cb3dSCy Schubert }
2102b15cb3dSCy Schubert 
2112b15cb3dSCy Schubert /* convert from l_fp type, relative signed/unsigned and absolute */
212*2d4e511cSCy Schubert extern struct timespec lfp_intv_to_tspec(l_fp x);
213*2d4e511cSCy Schubert extern struct timespec lfp_uintv_to_tspec(l_fp x);
2142b15cb3dSCy Schubert 
2152b15cb3dSCy Schubert /*
2162b15cb3dSCy Schubert  * absolute (timestamp) conversion. Input is time in NTP epoch, output
2172b15cb3dSCy Schubert  * is in UN*X epoch. The NTP time stamp will be expanded around the
2182b15cb3dSCy Schubert  * pivot time *p or the current time, if p is NULL.
2192b15cb3dSCy Schubert  */
220*2d4e511cSCy Schubert extern struct timespec lfp_stamp_to_tspec(l_fp x, const time_t *pivot);
2212b15cb3dSCy Schubert 
2222b15cb3dSCy Schubert #endif	/* TIMESPECOPS_H */
223