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