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 <time.h>
38 #include <stdbool.h>
39 
40 #define NSEC_PER_SEC 1000000000
41 
42 /**
43  * Add timespecs
44  *
45  * \param r[out] result: a + b
46  * \param a[in] operand
47  * \param b[in] operand
48  */
49 static inline void
timespec_add(struct timespec * r,const struct timespec * a,const struct timespec * b)50 timespec_add(struct timespec *r,
51              const struct timespec *a, const struct timespec *b)
52 {
53    r->tv_sec = a->tv_sec + b->tv_sec;
54    r->tv_nsec = a->tv_nsec + b->tv_nsec;
55    if (r->tv_nsec > NSEC_PER_SEC) {
56       r->tv_sec++;
57       r->tv_nsec -= NSEC_PER_SEC;
58    }
59 }
60 
61 /**
62  * Subtract timespecs
63  *
64  * \param r[out] result: a - b
65  * \param a[in] operand
66  * \param b[in] operand
67  */
68 static inline void
timespec_sub(struct timespec * r,const struct timespec * a,const struct timespec * b)69 timespec_sub(struct timespec *r,
70              const struct timespec *a, const struct timespec *b)
71 {
72    r->tv_sec = a->tv_sec - b->tv_sec;
73    r->tv_nsec = a->tv_nsec - b->tv_nsec;
74    if (r->tv_nsec < 0) {
75       r->tv_sec--;
76       r->tv_nsec += NSEC_PER_SEC;
77    }
78 }
79 
80 /**
81  * Add a nanosecond value to a timespec
82  *
83  * \param r[out] result: a + b
84  * \param a[in] base operand as timespec
85  * \param b[in] operand in nanoseconds
86  */
87 static inline void
timespec_add_nsec(struct timespec * r,const struct timespec * a,uint64_t b)88 timespec_add_nsec(struct timespec *r, const struct timespec *a, uint64_t b)
89 {
90    r->tv_sec = a->tv_sec + (b / NSEC_PER_SEC);
91    r->tv_nsec = a->tv_nsec + (b % NSEC_PER_SEC);
92 
93    if (r->tv_nsec >= NSEC_PER_SEC) {
94       r->tv_sec++;
95       r->tv_nsec -= NSEC_PER_SEC;
96    } else if (r->tv_nsec < 0) {
97       r->tv_sec--;
98       r->tv_nsec += NSEC_PER_SEC;
99    }
100 }
101 
102 /**
103  * Add a millisecond value to a timespec
104  *
105  * \param r[out] result: a + b
106  * \param a[in] base operand as timespec
107  * \param b[in] operand in milliseconds
108  */
109 static inline void
timespec_add_msec(struct timespec * r,const struct timespec * a,uint64_t b)110 timespec_add_msec(struct timespec *r, const struct timespec *a, uint64_t b)
111 {
112    timespec_add_nsec(r, a, b * 1000000);
113 }
114 
115 /**
116  * Convert timespec to nanoseconds
117  *
118  * \param a timespec
119  * \return nanoseconds
120  */
121 static inline uint64_t
timespec_to_nsec(const struct timespec * a)122 timespec_to_nsec(const struct timespec *a)
123 {
124    return (uint64_t)a->tv_sec * NSEC_PER_SEC + a->tv_nsec;
125 }
126 
127 /**
128  * Subtract timespecs and return result in nanoseconds
129  *
130  * \param a[in] operand
131  * \param b[in] operand
132  * \return to_nanoseconds(a - b)
133  */
134 static inline uint64_t
timespec_sub_to_nsec(const struct timespec * a,const struct timespec * b)135 timespec_sub_to_nsec(const struct timespec *a, const struct timespec *b)
136 {
137    struct timespec r;
138    timespec_sub(&r, a, b);
139    return timespec_to_nsec(&r);
140 }
141 
142 /**
143  * Convert timespec to milliseconds
144  *
145  * \param a timespec
146  * \return milliseconds
147  *
148  * Rounding to integer milliseconds happens always down (floor()).
149  */
150 static inline uint64_t
timespec_to_msec(const struct timespec * a)151 timespec_to_msec(const struct timespec *a)
152 {
153    return (uint64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000;
154 }
155 
156 /**
157  * Subtract timespecs and return result in milliseconds
158  *
159  * \param a[in] operand
160  * \param b[in] operand
161  * \return to_milliseconds(a - b)
162  */
163 static inline uint64_t
timespec_sub_to_msec(const struct timespec * a,const struct timespec * b)164 timespec_sub_to_msec(const struct timespec *a, const struct timespec *b)
165 {
166    return timespec_sub_to_nsec(a, b) / 1000000;
167 }
168 
169 /**
170  * Convert timespec to microseconds
171  *
172  * \param a timespec
173  * \return microseconds
174  *
175  * Rounding to integer microseconds happens always down (floor()).
176  */
177 static inline uint64_t
timespec_to_usec(const struct timespec * a)178 timespec_to_usec(const struct timespec *a)
179 {
180    return (uint64_t)a->tv_sec * 1000000 + a->tv_nsec / 1000;
181 }
182 
183 /**
184  * Convert timespec to protocol data
185  *
186  * \param a timespec
187  * \param tv_sec_hi[out] the high bytes of the seconds part
188  * \param tv_sec_lo[out] the low bytes of the seconds part
189  * \param tv_nsec[out] the nanoseconds part
190  *
191  * The input timespec must be normalized (the nanoseconds part should
192  * be less than 1 second) and non-negative.
193  */
194 static inline void
timespec_to_proto(const struct timespec * a,uint32_t * tv_sec_hi,uint32_t * tv_sec_lo,uint32_t * tv_nsec)195 timespec_to_proto(const struct timespec *a, uint32_t *tv_sec_hi,
196                   uint32_t *tv_sec_lo, uint32_t *tv_nsec)
197 {
198    assert(a->tv_sec >= 0);
199    assert(a->tv_nsec >= 0 && a->tv_nsec < NSEC_PER_SEC);
200 
201    uint64_t sec64 = a->tv_sec;
202 
203    *tv_sec_hi = sec64 >> 32;
204    *tv_sec_lo = sec64 & 0xffffffff;
205    *tv_nsec = a->tv_nsec;
206 }
207 
208 /**
209  * Convert nanoseconds to timespec
210  *
211  * \param a timespec
212  * \param b nanoseconds
213  */
214 static inline void
timespec_from_nsec(struct timespec * a,uint64_t b)215 timespec_from_nsec(struct timespec *a, uint64_t b)
216 {
217    a->tv_sec = b / NSEC_PER_SEC;
218    a->tv_nsec = b % NSEC_PER_SEC;
219 }
220 
221 /**
222  * Convert microseconds to timespec
223  *
224  * \param a timespec
225  * \param b microseconds
226  */
227 static inline void
timespec_from_usec(struct timespec * a,uint64_t b)228 timespec_from_usec(struct timespec *a, uint64_t b)
229 {
230    timespec_from_nsec(a, b * 1000);
231 }
232 
233 /**
234  * Convert milliseconds to timespec
235  *
236  * \param a timespec
237  * \param b milliseconds
238  */
239 static inline void
timespec_from_msec(struct timespec * a,uint64_t b)240 timespec_from_msec(struct timespec *a, uint64_t b)
241 {
242    timespec_from_nsec(a, b * 1000000);
243 }
244 
245 /**
246  * Convert protocol data to timespec
247  *
248  * \param a[out] timespec
249  * \param tv_sec_hi the high bytes of seconds part
250  * \param tv_sec_lo the low bytes of seconds part
251  * \param tv_nsec the nanoseconds part
252  */
253 static inline void
timespec_from_proto(struct timespec * a,uint32_t tv_sec_hi,uint32_t tv_sec_lo,uint32_t tv_nsec)254 timespec_from_proto(struct timespec *a, uint32_t tv_sec_hi,
255                     uint32_t tv_sec_lo, uint32_t tv_nsec)
256 {
257    a->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo;
258    a->tv_nsec = tv_nsec;
259 }
260 
261 /**
262  * Check if a timespec is zero
263  *
264  * \param a timespec
265  * \return whether the timespec is zero
266  */
267 static inline bool
timespec_is_zero(const struct timespec * a)268 timespec_is_zero(const struct timespec *a)
269 {
270    return a->tv_sec == 0 && a->tv_nsec == 0;
271 }
272 
273 /**
274  * Check if two timespecs are equal
275  *
276  * \param a[in] timespec to check
277  * \param b[in] timespec to check
278  * \return whether timespecs a and b are equal
279  */
280 static inline bool
timespec_eq(const struct timespec * a,const struct timespec * b)281 timespec_eq(const struct timespec *a, const struct timespec *b)
282 {
283    return a->tv_sec == b->tv_sec &&
284       a->tv_nsec == b->tv_nsec;
285 }
286 
287 /**
288  * Convert milli-Hertz to nanoseconds
289  *
290  * \param mhz frequency in mHz, not zero
291  * \return period in nanoseconds
292  */
293 static inline uint64_t
millihz_to_nsec(uint32_t mhz)294 millihz_to_nsec(uint32_t mhz)
295 {
296    assert(mhz > 0);
297    return 1000000000000LL / mhz;
298 }
299 
300 /**
301  * Checks whether a timespec value is after another
302  *
303  * \param a[in] timespec to compare
304  * \param b[in] timespec to compare
305  * \return whether a is after b
306  */
307 static inline bool
timespec_after(const struct timespec * a,const struct timespec * b)308 timespec_after(const struct timespec *a, const struct timespec *b)
309 {
310    return (a->tv_sec == b->tv_sec) ?
311       (a->tv_nsec > b->tv_nsec) :
312       (a->tv_sec > b->tv_sec);
313 }
314 
315 #ifndef _MSC_VER
316 /**
317  * Checks whether a timespec value is after the current time
318  *
319  * \param clock_domain[in] clock in which to do the comparison
320  * \param deadline[in] timespec to compare
321  * \return whether deadline is after the current time
322  */
323 static inline bool
timespec_passed(clockid_t clock_domain,const struct timespec * deadline)324 timespec_passed(clockid_t clock_domain, const struct timespec *deadline)
325 {
326    struct timespec current_time;
327    clock_gettime(clock_domain, &current_time);
328    return timespec_after(&current_time, deadline);
329 }
330 #endif
331 
332 #endif /* TIMESPEC_H */
333