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