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 */ 51static inline void 52timespec_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 */ 70static inline void 71timespec_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 */ 94static inline bool 95timespec_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 */ 127static inline bool 128timespec_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 */ 139static inline uint64_t 140timespec_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 */ 152static inline uint64_t 153timespec_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 */ 168static inline uint64_t 169timespec_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 */ 181static inline uint64_t 182timespec_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 */ 195static inline uint64_t 196timespec_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 */ 212static inline void 213timespec_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 */ 232static inline void 233timespec_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 */ 245static inline void 246timespec_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 */ 257static inline void 258timespec_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 */ 271static inline void 272timespec_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 */ 285static inline bool 286timespec_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 */ 298static inline bool 299timespec_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 */ 311static inline uint64_t 312millihz_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 */ 325static inline bool 326timespec_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