xref: /netbsd-src/external/bsd/ntp/dist/include/timespecops.h (revision cdfa2a7ef92791ba9db70a584a1d904730e6fb46)
1 /*	$NetBSD: timespecops.h,v 1.5 2020/05/25 20:47:20 christos Exp $	*/
2 
3 /*
4  * timespecops.h -- calculations on 'struct timespec' values
5  *
6  * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
7  * The contents of 'html/copyright.html' apply.
8  *
9  * Rationale
10  * ---------
11  *
12  * Doing basic arithmetic on a 'struct timespec' is not exceedingly
13  * hard, but it requires tedious and repetitive code to keep the result
14  * normalised. We consider a timespec normalised when the nanosecond
15  * fraction is in the interval [0 .. 10^9[ ; there are multiple value
16  * pairs of seconds and nanoseconds that denote the same time interval,
17  * but the normalised representation is unique. No two different
18  * intervals can have the same normalised representation.
19  *
20  * Another topic is the representation of negative time intervals.
21  * There's more than one way to this, since both the seconds and the
22  * nanoseconds of a timespec are signed values. IMHO, the easiest way is
23  * to use a complement representation where the nanoseconds are still
24  * normalised, no matter what the sign of the seconds value. This makes
25  * normalisation easier, since the sign of the integer part is
26  * irrelevant, and it removes several sign decision cases during the
27  * calculations.
28  *
29  * As long as no signed integer overflow can occur with the nanosecond
30  * part of the operands, all operations work as expected and produce a
31  * normalised result.
32  *
33  * The exception to this are functions fix a '_fast' suffix, which do no
34  * normalisation on input data and therefore expect the input data to be
35  * normalised.
36  *
37  * Input and output operands may overlap; all input is consumed before
38  * the output is written to.
39  */
40 #ifndef TIMESPECOPS_H
41 #define TIMESPECOPS_H
42 
43 #include <sys/types.h>
44 #include <stdio.h>
45 #include <math.h>
46 
47 #include "ntp.h"
48 #include "timetoa.h"
49 
50 
51 /* nanoseconds per second */
52 #define NANOSECONDS 1000000000
53 
54 /* predicate: returns TRUE if the nanoseconds are in nominal range */
55 #define timespec_isnormal(x) \
56 	((x)->tv_nsec >= 0 && (x)->tv_nsec < NANOSECONDS)
57 
58 /* predicate: returns TRUE if the nanoseconds are out-of-bounds */
59 #define timespec_isdenormal(x)	(!timespec_isnormal(x))
60 
61 
62 
63 
64 /* make sure nanoseconds are in nominal range */
65 extern struct timespec normalize_tspec(struct timespec x);
66 
67 /* x = a + b */
68 static inline struct timespec
add_tspec(struct timespec a,struct timespec b)69 add_tspec(
70 	struct timespec	a,
71 	struct timespec	b
72 	)
73 {
74 	struct timespec	x;
75 
76 	x = a;
77 	x.tv_sec += b.tv_sec;
78 	x.tv_nsec += b.tv_nsec;
79 
80 	return normalize_tspec(x);
81 }
82 
83 /* x = a + b, b is fraction only */
84 static inline struct timespec
add_tspec_ns(struct timespec a,long b)85 add_tspec_ns(
86 	struct timespec	a,
87 	long		b
88 	)
89 {
90 	struct timespec x;
91 
92 	x = a;
93 	x.tv_nsec += b;
94 
95 	return normalize_tspec(x);
96 }
97 
98 /* x = a - b */
99 static inline struct timespec
sub_tspec(struct timespec a,struct timespec b)100 sub_tspec(
101 	struct timespec	a,
102 	struct timespec	b
103 	)
104 {
105 	struct timespec x;
106 
107 	x = a;
108 	x.tv_sec -= b.tv_sec;
109 	x.tv_nsec -= b.tv_nsec;
110 
111 	return normalize_tspec(x);
112 }
113 
114 /* x = a - b, b is fraction only */
115 static inline struct timespec
sub_tspec_ns(struct timespec a,long b)116 sub_tspec_ns(
117 	struct timespec	a,
118 	long		b
119 	)
120 {
121 	struct timespec	x;
122 
123 	x = a;
124 	x.tv_nsec -= b;
125 
126 	return normalize_tspec(x);
127 }
128 
129 /* x = -a */
130 static inline struct timespec
neg_tspec(struct timespec a)131 neg_tspec(
132 	struct timespec	a
133 	)
134 {
135 	struct timespec	x;
136 
137 	x.tv_sec = -a.tv_sec;
138 	x.tv_nsec = -a.tv_nsec;
139 
140 	return normalize_tspec(x);
141 }
142 
143 /* x = abs(a) */
144 struct timespec abs_tspec(struct timespec a);
145 
146 /*
147  * compare previously-normalised a and b
148  * return 1 / 0 / -1 if a < / == / > b
149  */
150 extern int cmp_tspec(struct timespec a,	struct timespec b);
151 
152 /*
153  * compare possibly-denormal a and b
154  * return 1 / 0 / -1 if a < / == / > b
155  */
156 static inline int
cmp_tspec_denorm(struct timespec a,struct timespec b)157 cmp_tspec_denorm(
158 	struct timespec	a,
159 	struct timespec	b
160 	)
161 {
162 	return cmp_tspec(normalize_tspec(a), normalize_tspec(b));
163 }
164 
165 /*
166  * test previously-normalised a
167  * return 1 / 0 / -1 if a < / == / > 0
168  */
169 extern int test_tspec(struct timespec a);
170 
171 /*
172  * test possibly-denormal a
173  * return 1 / 0 / -1 if a < / == / > 0
174  */
175 static inline int
test_tspec_denorm(struct timespec a)176 test_tspec_denorm(
177 	struct timespec	a
178 	)
179 {
180 	return test_tspec(normalize_tspec(a));
181 }
182 
183 /* return LIB buffer ptr to string rep */
184 static inline const char *
tspectoa(struct timespec x)185 tspectoa(
186 	struct timespec	x
187 	)
188 {
189 	return format_time_fraction(x.tv_sec, x.tv_nsec, 9);
190 }
191 
192 /*
193  *  convert to l_fp type, relative and absolute
194  */
195 
196 /* convert from timespec duration to l_fp duration */
197 extern l_fp tspec_intv_to_lfp(struct timespec x);
198 
199 /* x must be UN*X epoch, output will be in NTP epoch */
200 static inline l_fp
tspec_stamp_to_lfp(struct timespec x)201 tspec_stamp_to_lfp(
202 	struct timespec	x
203 	)
204 {
205 	l_fp		y;
206 
207 	y = tspec_intv_to_lfp(x);
208 	y.l_ui += JAN_1970;
209 
210 	return y;
211 }
212 
213 /* convert from l_fp type, relative signed/unsigned and absolute */
214 extern struct timespec lfp_intv_to_tspec(l_fp x);
215 extern struct timespec lfp_uintv_to_tspec(l_fp x);
216 
217 /*
218  * absolute (timestamp) conversion. Input is time in NTP epoch, output
219  * is in UN*X epoch. The NTP time stamp will be expanded around the
220  * pivot time *p or the current time, if p is NULL.
221  */
222 extern struct timespec lfp_stamp_to_tspec(l_fp x, const time_t *pivot);
223 
224 #endif	/* TIMESPECOPS_H */
225