123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- /*
- * This file is Copyright (c) 2015 by the GPSD project
- * SPDX-License-Identifier: BSD-2-clause
- */
- #ifndef GPSD_TIMESPEC_H
- #define GPSD_TIMESPEC_H
- #include <math.h> /* for modf() */
- #include <stdbool.h> /* for bool */
- /* normalize a timespec
- *
- * three cases to note
- * if tv_sec is positve, then tv_nsec must be positive
- * if tv_sec is negative, then tv_nsec must be negative
- * if tv_sec is zero, then tv_nsec may be positive or negative.
- *
- * this only handles the case where two normalized timespecs
- * are added or subracted. (e.g. only a one needs to be borrowed/carried
- *
- * NOTE: this normalization is not the same as ntpd uses
- */
- #define NS_IN_SEC 1000000000LL /* nanoseconds in a second */
- #define US_IN_SEC 1000000LL /* microseconds in a second */
- #define MS_IN_SEC 1000LL /* milliseconds in a second */
- /* return the difference between timespecs in nanoseconds
- * int may be too small, 32 bit long is too small, floats are too imprecise,
- * doubles are not quite precise enough
- * MUST be at least int64_t to maintain precision on 32 bit code */
- #define timespec_diff_ns(x, y) \
- (int64_t)((((x).tv_sec-(y).tv_sec)*NS_IN_SEC)+(x).tv_nsec-(y).tv_nsec)
- static inline void TS_NORM( struct timespec *ts)
- {
- if ( ( 1 <= ts->tv_sec ) ||
- ( (0 == ts->tv_sec ) && (0 <= ts->tv_nsec ) ) ) {
- /* result is positive */
- if ( NS_IN_SEC <= ts->tv_nsec ) {
- /* borrow from tv_sec */
- ts->tv_nsec -= NS_IN_SEC;
- ts->tv_sec++;
- } else if ( 0 > (ts)->tv_nsec ) {
- /* carry to tv_sec */
- ts->tv_nsec += NS_IN_SEC;
- ts->tv_sec--;
- }
- } else {
- /* result is negative */
- if ( -NS_IN_SEC >= ts->tv_nsec ) {
- /* carry to tv_sec */
- ts->tv_nsec += NS_IN_SEC;
- ts->tv_sec--;
- } else if ( 0 < ts->tv_nsec ) {
- /* borrow from tv_sec */
- ts->tv_nsec -= NS_IN_SEC;
- ts->tv_sec++;
- }
- }
- }
- /* normalize a timeval */
- #define TV_NORM(tv) \
- do { \
- if ( US_IN_SEC <= (tv)->tv_usec ) { \
- (tv)->tv_usec -= US_IN_SEC; \
- (tv)->tv_sec++; \
- } else if ( 0 > (tv)->tv_usec ) { \
- (tv)->tv_usec += US_IN_SEC; \
- (tv)->tv_sec--; \
- } \
- } while (0)
- /* convert timespec to timeval, with rounding */
- #define TSTOTV(tv, ts) \
- do { \
- (tv)->tv_sec = (ts)->tv_sec; \
- (tv)->tv_usec = ((ts)->tv_nsec + 500)/1000; \
- TV_NORM( tv ); \
- } while (0)
- /* convert timeval to timespec */
- #define TVTOTS(ts, tv) \
- do { \
- (ts)->tv_sec = (tv)->tv_sec; \
- (ts)->tv_nsec = (tv)->tv_usec*1000; \
- TS_NORM( ts ); \
- } while (0)
- /* subtract two timespec */
- #define TS_SUB(r, ts1, ts2) \
- do { \
- (r)->tv_sec = (ts1)->tv_sec - (ts2)->tv_sec; \
- (r)->tv_nsec = (ts1)->tv_nsec - (ts2)->tv_nsec; \
- TS_NORM( r ); \
- } while (0)
- /* subtract two timespec, return a double */
- #define TS_SUB_D(ts1, ts2) \
- ((double)((ts1)->tv_sec - (ts2)->tv_sec) + \
- ((double)((ts1)->tv_nsec - (ts2)->tv_nsec) * 1e-9))
- // true if normalized timespec is non zero
- #define TS_NZ(ts) (0 != (ts)->tv_sec || 0 != (ts)->tv_nsec)
- // true if normalized timespec equal or greater than zero
- #define TS_GEZ(ts) (0 <= (ts)->tv_sec && 0 <= (ts)->tv_nsec)
- // true if normalized timespec greater than zero
- #define TS_GZ(ts) (0 < (ts)->tv_sec || 0 < (ts)->tv_nsec)
- // true if normalized timespec1 greater than timespec2
- #define TS_GT(ts1, ts2) ((ts1)->tv_sec > (ts2)->tv_sec || \
- ((ts1)->tv_sec == (ts2)->tv_sec && \
- (ts1)->tv_nsec > (ts2)->tv_nsec))
- // true if normalized timespec1 greater or equal to timespec2
- #define TS_GE(ts1, ts2) ((ts1)->tv_sec > (ts2)->tv_sec || \
- ((ts1)->tv_sec == (ts2)->tv_sec && \
- (ts1)->tv_nsec >= (ts2)->tv_nsec))
- // true if normalized timespec1 equal to timespec2
- #define TS_EQ(ts1, ts2) ((ts1)->tv_sec == (ts2)->tv_sec && \
- (ts1)->tv_nsec == (ts2)->tv_nsec)
- /* convert a timespec to a double.
- * if tv_sec > 2, then inevitable loss of precision in tv_nsec
- * so best to NEVER use TSTONS()
- * WARNING replacing 1e9 with NS_IN_SEC causes loss of precision */
- #define TSTONS(ts) ((double)((ts)->tv_sec + ((ts)->tv_nsec / 1e9)))
- /* convert a double to a timespec_t
- * if D > 2, then inevitable loss of precision in nanoseconds
- */
- #define DTOTS(ts, d) \
- do { \
- double int_part; \
- (ts)->tv_nsec = (long)(modf(d, &int_part) * 1e9); \
- (ts)->tv_sec = (time_t)int_part; \
- } while (0)
- /* convert integer (64 bit for full range) ms to a timespec_t */
- #define MSTOTS(ts, ms) \
- do { \
- (ts)->tv_sec = (time_t)(ms / 1000); \
- (ts)->tv_nsec = (long)((ms % 1000) * 1000000L); \
- } while (0)
- #define TIMESPEC_LEN 22 /* required length of a timespec buffer */
- extern const char *timespec_str(const struct timespec *, char *, size_t);
- bool nanowait(int, int);
- #endif /* GPSD_TIMESPEC_H */
- /* end */
|