util/timespec: use unsigned 64 bit integers for nsec values
[mesa.git] / src / util / timespec.h
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 /**
316 * Checks whether a timespec value is after the current time
317 *
318 * \param clock_domain[in] clock in which to do the comparison
319 * \param deadline[in] timespec to compare
320 * \return whether deadline is after the current time
321 */
322 static inline bool
323 timespec_passed(clockid_t clock_domain, const struct timespec *deadline)
324 {
325 struct timespec current_time;
326 clock_gettime(clock_domain, &current_time);
327 return timespec_after(&current_time, deadline);
328 }
329
330 #endif /* TIMESPEC_H */