1 /*
2 * Copyright © 2014 - 2015 Collabora, Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 /**
27 * \file timespec.h
28 *
29 * Helpers to deal with timespec structures.
30 */
31
32 #ifndef TIMESPEC_H
33 #define TIMESPEC_H
34
35 #include <stdint.h>
36 #include <assert.h>
37 #include <stdbool.h>
38
39 #include "c11/time.h"
40 #include "macros.h"
41
42 #define NSEC_PER_SEC 1000000000
43
44 /**
45 * Add timespecs
46 *
47 * \param r[out] result: a + b
48 * \param a[in] operand
49 * \param b[in] operand
50 */
51 static inline void
timespec_add(struct timespec * r,const struct timespec * a,const struct timespec * b)52 timespec_add(struct timespec *r,
53 const struct timespec *a, const struct timespec *b)
54 {
55 r->tv_sec = a->tv_sec + b->tv_sec;
56 r->tv_nsec = a->tv_nsec + b->tv_nsec;
57 if (r->tv_nsec > NSEC_PER_SEC) {
58 r->tv_sec++;
59 r->tv_nsec -= NSEC_PER_SEC;
60 }
61 }
62
63 /**
64 * Subtract timespecs
65 *
66 * \param r[out] result: a - b
67 * \param a[in] operand
68 * \param b[in] operand
69 */
70 static inline void
timespec_sub(struct timespec * r,const struct timespec * a,const struct timespec * b)71 timespec_sub(struct timespec *r,
72 const struct timespec *a, const struct timespec *b)
73 {
74 r->tv_sec = a->tv_sec - b->tv_sec;
75 r->tv_nsec = a->tv_nsec - b->tv_nsec;
76 if (r->tv_nsec < 0) {
77 r->tv_sec--;
78 r->tv_nsec += NSEC_PER_SEC;
79 }
80 }
81
82 /**
83 * Saturating timespec subtraction
84 *
85 * \param r[out] result: max(a - b, 0)
86 * \param a[in] operand
87 * \param b[in] operand
88 */
89 static inline void
timespec_sub_saturate(struct timespec * r,const struct timespec * a,const struct timespec * b)90 timespec_sub_saturate(struct timespec *r,
91 const struct timespec *a, const struct timespec *b)
92 {
93 timespec_sub(r, a, b);
94 if (r->tv_sec < 0) {
95 r->tv_sec = 0;
96 r->tv_nsec = 0;
97 }
98 }
99
100 #define TIME_T_MAX \
101 ((time_t)(((time_t)-1) > 0 ? u_uintN_max(sizeof(time_t) * 8) : \
102 u_intN_max(sizeof(time_t) * 8)))
103
104 /**
105 * Add a nanosecond value to a timespec
106 *
107 * \param r[out] result: a + b
108 * \param a[in] base operand as timespec
109 * \param b[in] operand in nanoseconds
110 * \return true if the calculation overflowed
111 */
112 static inline bool
timespec_add_nsec(struct timespec * r,const struct timespec * a,uint64_t b)113 timespec_add_nsec(struct timespec *r, const struct timespec *a, uint64_t b)
114 {
115 uint64_t b_sec = b / NSEC_PER_SEC;
116 long b_nsec = b % NSEC_PER_SEC;
117 bool overflow = (b_sec > (uint64_t)TIME_T_MAX) ||
118 ((uint64_t)a->tv_sec > (uint64_t)TIME_T_MAX - b_sec);
119
120 r->tv_sec = (uint64_t)a->tv_sec + b_sec;
121 r->tv_nsec = (uint64_t)a->tv_nsec + b_nsec;
122
123 if (r->tv_nsec >= NSEC_PER_SEC) {
124 if (r->tv_sec >= TIME_T_MAX)
125 overflow = true;
126 r->tv_sec = (uint64_t)r->tv_sec + 1ull;
127 r->tv_nsec -= NSEC_PER_SEC;
128 } else if (r->tv_nsec < 0) {
129 assert(overflow);
130 r->tv_sec--;
131 r->tv_nsec += NSEC_PER_SEC;
132 }
133
134 return overflow;
135 }
136
137 /**
138 * Add a millisecond value to a timespec
139 *
140 * \param r[out] result: a + b
141 * \param a[in] base operand as timespec
142 * \param b[in] operand in milliseconds
143 * \return true if the calculation overflowed
144 */
145 static inline bool
timespec_add_msec(struct timespec * r,const struct timespec * a,uint64_t b)146 timespec_add_msec(struct timespec *r, const struct timespec *a, uint64_t b)
147 {
148 return timespec_add_nsec(r, a, b * 1000000) || b > (UINT64_MAX / 1000000);
149 }
150
151 /**
152 * Convert timespec to nanoseconds
153 *
154 * \param a timespec
155 * \return nanoseconds
156 */
157 static inline uint64_t
timespec_to_nsec(const struct timespec * a)158 timespec_to_nsec(const struct timespec *a)
159 {
160 return (uint64_t)a->tv_sec * NSEC_PER_SEC + a->tv_nsec;
161 }
162
163 /**
164 * Subtract timespecs and return result in nanoseconds
165 *
166 * \param a[in] operand
167 * \param b[in] operand
168 * \return to_nanoseconds(a - b)
169 */
170 static inline uint64_t
timespec_sub_to_nsec(const struct timespec * a,const struct timespec * b)171 timespec_sub_to_nsec(const struct timespec *a, const struct timespec *b)
172 {
173 struct timespec r;
174 timespec_sub(&r, a, b);
175 return timespec_to_nsec(&r);
176 }
177
178 /**
179 * Convert timespec to milliseconds
180 *
181 * \param a timespec
182 * \return milliseconds
183 *
184 * Rounding to integer milliseconds happens always down (floor()).
185 */
186 static inline uint64_t
timespec_to_msec(const struct timespec * a)187 timespec_to_msec(const struct timespec *a)
188 {
189 return (uint64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000;
190 }
191
192 /**
193 * Subtract timespecs and return result in milliseconds
194 *
195 * \param a[in] operand
196 * \param b[in] operand
197 * \return to_milliseconds(a - b)
198 */
199 static inline uint64_t
timespec_sub_to_msec(const struct timespec * a,const struct timespec * b)200 timespec_sub_to_msec(const struct timespec *a, const struct timespec *b)
201 {
202 return timespec_sub_to_nsec(a, b) / 1000000;
203 }
204
205 /**
206 * Convert timespec to microseconds
207 *
208 * \param a timespec
209 * \return microseconds
210 *
211 * Rounding to integer microseconds happens always down (floor()).
212 */
213 static inline uint64_t
timespec_to_usec(const struct timespec * a)214 timespec_to_usec(const struct timespec *a)
215 {
216 return (uint64_t)a->tv_sec * 1000000 + a->tv_nsec / 1000;
217 }
218
219 /**
220 * Convert timespec to protocol data
221 *
222 * \param a timespec
223 * \param tv_sec_hi[out] the high bytes of the seconds part
224 * \param tv_sec_lo[out] the low bytes of the seconds part
225 * \param tv_nsec[out] the nanoseconds part
226 *
227 * The input timespec must be normalized (the nanoseconds part should
228 * be less than 1 second) and non-negative.
229 */
230 static inline void
timespec_to_proto(const struct timespec * a,uint32_t * tv_sec_hi,uint32_t * tv_sec_lo,uint32_t * tv_nsec)231 timespec_to_proto(const struct timespec *a, uint32_t *tv_sec_hi,
232 uint32_t *tv_sec_lo, uint32_t *tv_nsec)
233 {
234 assert(a->tv_sec >= 0);
235 assert(a->tv_nsec >= 0 && a->tv_nsec < NSEC_PER_SEC);
236
237 uint64_t sec64 = a->tv_sec;
238
239 *tv_sec_hi = sec64 >> 32;
240 *tv_sec_lo = sec64 & 0xffffffff;
241 *tv_nsec = a->tv_nsec;
242 }
243
244 /**
245 * Convert nanoseconds to timespec
246 *
247 * \param a timespec
248 * \param b nanoseconds
249 */
250 static inline void
timespec_from_nsec(struct timespec * a,uint64_t b)251 timespec_from_nsec(struct timespec *a, uint64_t b)
252 {
253 a->tv_sec = b / NSEC_PER_SEC;
254 a->tv_nsec = b % NSEC_PER_SEC;
255 }
256
257 /**
258 * Convert microseconds to timespec
259 *
260 * \param a timespec
261 * \param b microseconds
262 */
263 static inline void
timespec_from_usec(struct timespec * a,uint64_t b)264 timespec_from_usec(struct timespec *a, uint64_t b)
265 {
266 timespec_from_nsec(a, b * 1000);
267 }
268
269 /**
270 * Convert milliseconds to timespec
271 *
272 * \param a timespec
273 * \param b milliseconds
274 */
275 static inline void
timespec_from_msec(struct timespec * a,uint64_t b)276 timespec_from_msec(struct timespec *a, uint64_t b)
277 {
278 timespec_from_nsec(a, b * 1000000);
279 }
280
281 /**
282 * Convert protocol data to timespec
283 *
284 * \param a[out] timespec
285 * \param tv_sec_hi the high bytes of seconds part
286 * \param tv_sec_lo the low bytes of seconds part
287 * \param tv_nsec the nanoseconds part
288 */
289 static inline void
timespec_from_proto(struct timespec * a,uint32_t tv_sec_hi,uint32_t tv_sec_lo,uint32_t tv_nsec)290 timespec_from_proto(struct timespec *a, uint32_t tv_sec_hi,
291 uint32_t tv_sec_lo, uint32_t tv_nsec)
292 {
293 a->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo;
294 a->tv_nsec = tv_nsec;
295 }
296
297 /**
298 * Check if a timespec is zero
299 *
300 * \param a timespec
301 * \return whether the timespec is zero
302 */
303 static inline bool
timespec_is_zero(const struct timespec * a)304 timespec_is_zero(const struct timespec *a)
305 {
306 return a->tv_sec == 0 && a->tv_nsec == 0;
307 }
308
309 /**
310 * Check if two timespecs are equal
311 *
312 * \param a[in] timespec to check
313 * \param b[in] timespec to check
314 * \return whether timespecs a and b are equal
315 */
316 static inline bool
timespec_eq(const struct timespec * a,const struct timespec * b)317 timespec_eq(const struct timespec *a, const struct timespec *b)
318 {
319 return a->tv_sec == b->tv_sec &&
320 a->tv_nsec == b->tv_nsec;
321 }
322
323 /**
324 * Convert milli-Hertz to nanoseconds
325 *
326 * \param mhz frequency in mHz, not zero
327 * \return period in nanoseconds
328 */
329 static inline uint64_t
millihz_to_nsec(uint32_t mhz)330 millihz_to_nsec(uint32_t mhz)
331 {
332 assert(mhz > 0);
333 return 1000000000000LL / mhz;
334 }
335
336 /**
337 * Checks whether a timespec value is after another
338 *
339 * \param a[in] timespec to compare
340 * \param b[in] timespec to compare
341 * \return whether a is after b
342 */
343 static inline bool
timespec_after(const struct timespec * a,const struct timespec * b)344 timespec_after(const struct timespec *a, const struct timespec *b)
345 {
346 return (a->tv_sec == b->tv_sec) ?
347 (a->tv_nsec > b->tv_nsec) :
348 (a->tv_sec > b->tv_sec);
349 }
350
351 #endif /* TIMESPEC_H */
352