#ifndef INCLUDED_C_TIMESPEC_H #define INCLUDED_C_TIMESPEC_H #ifndef INCLUDED_C_TYPES_H #include #endif /*INCLUDED_C_TYPES_H*/ /* ------------------------------------------------------------------------------------------------------------------ */ /* */ #define C_NSEC_PER_USEC 1000L #define C_USEC_PER_MSEC 1000L #define C_MSEC_PER_SEC 1000L #define C_NSEC_PER_MSEC 1000000L #define C_USEC_PER_SEC 1000000L #define C_NSEC_PER_SEC 1000000000L /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE struct timespec c_timespec_normalise(struct timespec ts) { while(ts.tv_nsec >= C_NSEC_PER_SEC) { ++(ts.tv_sec); ts.tv_nsec -= C_NSEC_PER_SEC; } while(ts.tv_nsec <= -C_NSEC_PER_SEC) { --(ts.tv_sec); ts.tv_nsec += C_NSEC_PER_SEC; } if(ts.tv_nsec < 0) { /* Negative nanoseconds isn't valid according to POSIX. * Decrement tv_sec and roll tv_nsec over. */ --(ts.tv_sec); ts.tv_nsec = (C_NSEC_PER_SEC + ts.tv_nsec); } return ts; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE struct timespec c_timespec_add(struct timespec ts1, struct timespec ts2) { /* Normalise inputs to prevent tv_nsec rollover if whole-second values * are packed in it. */ ts1 = c_timespec_normalise(ts1); ts2 = c_timespec_normalise(ts2); ts1.tv_sec += ts2.tv_sec; ts1.tv_nsec += ts2.tv_nsec; return c_timespec_normalise(ts1); } C_STATIC_FORCE_INLINE struct timespec c_timespec_sub(struct timespec ts1, struct timespec ts2) { /* Normalise inputs to prevent tv_nsec rollover if whole-second values * are packed in it. */ ts1 = c_timespec_normalise(ts1); ts2 = c_timespec_normalise(ts2); ts1.tv_sec -= ts2.tv_sec; ts1.tv_nsec -= ts2.tv_nsec; return c_timespec_normalise(ts1); } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE int c_timespec_cmp(struct timespec ts1, struct timespec ts2) { ts1 = c_timespec_normalise(ts1); ts2 = c_timespec_normalise(ts2); if(ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec == ts2.tv_nsec) { return 0; } else if((ts1.tv_sec > ts2.tv_sec) || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec > ts2.tv_nsec)) { return 1; } else { return -1; } } C_STATIC_FORCE_INLINE bool c_timespec_eq(struct timespec ts1, struct timespec ts2) { ts1 = c_timespec_normalise(ts1); ts2 = c_timespec_normalise(ts2); return (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec == ts2.tv_nsec); } C_STATIC_FORCE_INLINE bool c_timespec_gt(struct timespec ts1, struct timespec ts2) { ts1 = c_timespec_normalise(ts1); ts2 = c_timespec_normalise(ts2); return (ts1.tv_sec > ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec > ts2.tv_nsec)); } C_STATIC_FORCE_INLINE bool c_timespec_ge(struct timespec ts1, struct timespec ts2) { ts1 = c_timespec_normalise(ts1); ts2 = c_timespec_normalise(ts2); return (ts1.tv_sec > ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec >= ts2.tv_nsec)); } C_STATIC_FORCE_INLINE bool c_timespec_lt(struct timespec ts1, struct timespec ts2) { ts1 = c_timespec_normalise(ts1); ts2 = c_timespec_normalise(ts2); return (ts1.tv_sec < ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec < ts2.tv_nsec)); } C_STATIC_FORCE_INLINE bool c_timespec_le(struct timespec ts1, struct timespec ts2) { ts1 = c_timespec_normalise(ts1); ts2 = c_timespec_normalise(ts2); return (ts1.tv_sec < ts2.tv_sec || (ts1.tv_sec == ts2.tv_sec && ts1.tv_nsec <= ts2.tv_nsec)); } C_STATIC_FORCE_INLINE struct timespec c_timespec_min(struct timespec ts1, struct timespec ts2) { if(c_timespec_le(ts1, ts2)) { return ts1; } else { return ts2; } } C_STATIC_FORCE_INLINE struct timespec c_timespec_max(struct timespec ts1, struct timespec ts2) { if(c_timespec_ge(ts1, ts2)) { return ts1; } else { return ts2; } } C_STATIC_FORCE_INLINE struct timespec c_timespec_clamp(struct timespec ts, struct timespec min, struct timespec max) { if(c_timespec_gt(ts, max)) { return max; } if(c_timespec_lt(ts, min)) { return min; } return ts; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE struct timespec c_timespec_from_double(double s) { struct timespec ts = { .tv_sec = s, .tv_nsec = (s - (long)(s)) * C_NSEC_PER_SEC, }; return c_timespec_normalise(ts); } C_STATIC_FORCE_INLINE double c_timespec_to_double(struct timespec ts) { return ((double)(ts.tv_sec) + ((double)(ts.tv_nsec) / C_NSEC_PER_SEC)); } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE struct timespec c_timespec_from_timeval(struct timeval tv) { struct timespec ts = { .tv_sec = tv.tv_sec, .tv_nsec = tv.tv_usec * C_NSEC_PER_USEC }; return c_timespec_normalise(ts); } C_STATIC_FORCE_INLINE struct timeval c_timespec_to_timeval(struct timespec ts) { ts = c_timespec_normalise(ts); struct timeval tv = { .tv_sec = ts.tv_sec, .tv_usec = ts.tv_nsec / C_NSEC_PER_USEC, }; return tv; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE struct timespec c_timespec_from_ms(long milliseconds) { struct timespec ts = { .tv_sec = (milliseconds / C_MSEC_PER_SEC), .tv_nsec = (milliseconds % C_MSEC_PER_SEC) * C_NSEC_PER_MSEC, }; return c_timespec_normalise(ts); } C_STATIC_FORCE_INLINE long c_timespec_to_ms(struct timespec ts) { return (ts.tv_sec * C_MSEC_PER_SEC) + (ts.tv_nsec / C_NSEC_PER_MSEC); } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ struct timespec c_timespec_mod(struct timespec ts1, struct timespec ts2); #endif /*INCLUDED_C_TIMESPEC_H*/