timespec.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * This file is Copyright 2015 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #ifndef GPSD_TIMESPEC_H
  6. #define GPSD_TIMESPEC_H
  7. #include <math.h> /* for modf() */
  8. #include <stdbool.h> /* for bool */
  9. #define NS_IN_SEC 1000000000LL /* nanoseconds in a second */
  10. #define MS_IN_NS 1000000LL /* milliseconds in a nano second */
  11. #define US_IN_SEC 1000000LL /* microseconds in a second */
  12. #define MS_IN_SEC 1000LL /* milliseconds in a second */
  13. /* convert a timespec_t to an int64_t of milli seconds */
  14. #define TSTOMS(ts) ((int64_t)((ts)->tv_sec) * MS_IN_SEC + \
  15. (int64_t)((ts)->tv_nsec / MS_IN_NS))
  16. /* normalize a timespec
  17. *
  18. * three cases to note
  19. * if tv_sec is positive, then tv_nsec must be positive
  20. * if tv_sec is negative, then tv_nsec must be negative
  21. * if tv_sec is zero, then tv_nsec may be positive or negative.
  22. *
  23. * this only handles the case where two normalized timespecs
  24. * are added or subtracted. (e.g. only a one needs to be borrowed/carried
  25. *
  26. * NOTE: this normalization is not the same as ntpd uses
  27. */
  28. /* return the difference between timespecs in nanoseconds
  29. * int may be too small, 32 bit long is too small, floats are too imprecise,
  30. * doubles are not quite precise enough
  31. * MUST be at least int64_t to maintain precision on 32 bit code */
  32. #define timespec_diff_ns(x, y) \
  33. (int64_t)((((x).tv_sec-(y).tv_sec)*NS_IN_SEC)+(x).tv_nsec-(y).tv_nsec)
  34. static inline void TS_NORM( struct timespec *ts)
  35. {
  36. if ( ( 1 <= ts->tv_sec ) ||
  37. ( (0 == ts->tv_sec ) && (0 <= ts->tv_nsec ) ) ) {
  38. /* result is positive */
  39. if ( NS_IN_SEC <= ts->tv_nsec ) {
  40. /* borrow from tv_sec */
  41. ts->tv_nsec -= NS_IN_SEC;
  42. ts->tv_sec++;
  43. } else if ( 0 > (ts)->tv_nsec ) {
  44. /* carry to tv_sec */
  45. ts->tv_nsec += NS_IN_SEC;
  46. ts->tv_sec--;
  47. }
  48. } else {
  49. /* result is negative */
  50. if ( -NS_IN_SEC >= ts->tv_nsec ) {
  51. /* carry to tv_sec */
  52. ts->tv_nsec += NS_IN_SEC;
  53. ts->tv_sec--;
  54. } else if ( 0 < ts->tv_nsec ) {
  55. /* borrow from tv_sec */
  56. ts->tv_nsec -= NS_IN_SEC;
  57. ts->tv_sec++;
  58. }
  59. }
  60. }
  61. /* normalize a timeval */
  62. #define TV_NORM(tv) \
  63. do { \
  64. if ( US_IN_SEC <= (tv)->tv_usec ) { \
  65. (tv)->tv_usec -= US_IN_SEC; \
  66. (tv)->tv_sec++; \
  67. } else if ( 0 > (tv)->tv_usec ) { \
  68. (tv)->tv_usec += US_IN_SEC; \
  69. (tv)->tv_sec--; \
  70. } \
  71. } while (0)
  72. /* convert timespec to timeval, with rounding */
  73. #define TSTOTV(tv, ts) \
  74. do { \
  75. (tv)->tv_sec = (ts)->tv_sec; \
  76. (tv)->tv_usec = ((ts)->tv_nsec + 500)/1000; \
  77. TV_NORM( tv ); \
  78. } while (0)
  79. /* convert timeval to timespec */
  80. #define TVTOTS(ts, tv) \
  81. do { \
  82. (ts)->tv_sec = (tv)->tv_sec; \
  83. (ts)->tv_nsec = (tv)->tv_usec*1000; \
  84. TS_NORM( ts ); \
  85. } while (0)
  86. /* subtract two timespec */
  87. #define TS_SUB(r, ts1, ts2) \
  88. do { \
  89. (r)->tv_sec = (ts1)->tv_sec - (ts2)->tv_sec; \
  90. (r)->tv_nsec = (ts1)->tv_nsec - (ts2)->tv_nsec; \
  91. TS_NORM( r ); \
  92. } while (0)
  93. /* subtract two timespec, return a double */
  94. #define TS_SUB_D(ts1, ts2) \
  95. ((double)((ts1)->tv_sec - (ts2)->tv_sec) + \
  96. ((double)((ts1)->tv_nsec - (ts2)->tv_nsec) * 1e-9))
  97. // true if normalized timespec is non zero
  98. #define TS_NZ(ts) (0 != (ts)->tv_sec || 0 != (ts)->tv_nsec)
  99. // true if normalized timespec equal or greater than zero
  100. #define TS_GEZ(ts) (0 <= (ts)->tv_sec && 0 <= (ts)->tv_nsec)
  101. // true if normalized timespec greater than zero
  102. #define TS_GZ(ts) (0 < (ts)->tv_sec || 0 < (ts)->tv_nsec)
  103. // true if normalized timespec1 greater than timespec2
  104. #define TS_GT(ts1, ts2) ((ts1)->tv_sec > (ts2)->tv_sec || \
  105. ((ts1)->tv_sec == (ts2)->tv_sec && \
  106. (ts1)->tv_nsec > (ts2)->tv_nsec))
  107. // true if normalized timespec1 greater or equal to timespec2
  108. #define TS_GE(ts1, ts2) ((ts1)->tv_sec > (ts2)->tv_sec || \
  109. ((ts1)->tv_sec == (ts2)->tv_sec && \
  110. (ts1)->tv_nsec >= (ts2)->tv_nsec))
  111. // true if normalized timespec1 equal to timespec2
  112. #define TS_EQ(ts1, ts2) ((ts1)->tv_sec == (ts2)->tv_sec && \
  113. (ts1)->tv_nsec == (ts2)->tv_nsec)
  114. /* convert a timespec to a double.
  115. * if tv_sec > 2, then inevitable loss of precision in tv_nsec
  116. * so best to NEVER use TSTONS()
  117. * WARNING replacing 1e9 with NS_IN_SEC causes loss of precision */
  118. #define TSTONS(ts) ((double)((ts)->tv_sec + ((ts)->tv_nsec / 1e9)))
  119. /* convert a double to a timespec_t
  120. * if D > 2, then inevitable loss of precision in nanoseconds
  121. */
  122. #define DTOTS(ts, d) \
  123. do { \
  124. double int_part; \
  125. (ts)->tv_nsec = (long)(modf(d, &int_part) * 1e9); \
  126. (ts)->tv_sec = (time_t)int_part; \
  127. } while (0)
  128. /* convert integer (64 bit for full range) ms to a timespec_t */
  129. #define MSTOTS(ts, ms) \
  130. do { \
  131. (ts)->tv_sec = (time_t)(ms / 1000); \
  132. (ts)->tv_nsec = (long)((ms % 1000) * 1000000L); \
  133. } while (0)
  134. /* convert integer (64 bit for full range) us to a timespec_t */
  135. #define USTOTS(ts, ms) \
  136. do { \
  137. (ts)->tv_sec = (time_t)(ms / 1000000); \
  138. (ts)->tv_nsec = (long)((ms % 1000000) * 1000L); \
  139. } while (0)
  140. #define TIMESPEC_LEN 22 /* required length of a timespec buffer */
  141. extern const char *timespec_str(const struct timespec *, char *, size_t);
  142. bool nanowait(int, struct timespec *);
  143. #endif /* GPSD_TIMESPEC_H */
  144. /* end */
  145. // vim: set expandtab shiftwidth=4