#ifndef _D_TIMING_H #define _D_TIMING_H #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 199309L #endif #include #include #include #ifdef CLOCK_MONOTONIC_RAW #define BEST_CLOCK_SOURCE CLOCK_MONOTONIC_RAW #else #define BEST_CLOCK_SOURCE CLOCK_MONOTONIC #endif typedef struct timespec ticks; extern struct timespec basetime; /** * Assign src to dst while adding secs seconds. */ #define timing_set(dst,src,secs) do { (dst)->tv_sec = (src)->tv_sec + secs; (dst)->tv_nsec = (src)->tv_nsec; } while (0) /** * Define variable now, initialize to timing_get. */ #define declare_now ticks now; timing_get( &now ) /** * Call this once to calibrate on startup. * Although overflows of CLOCK_MONOTONIC(_RAW) should * by definition never happen, we still have a fixed size * int that could at some point. By forcing the counter * to start at 0 on startup the point of overflow * will be very far in the future (decades for 32bit time_t, * end of universe for 64bit). */ void timing_setBase(); /** * Internal, do not use. Moved to another function * to prevent inlining of error handling code, which * should be very unlikely to ever trigger. */ _Noreturn void timing_abort(); /** * Get current time. Shortcut for clock_gettime with error check. */ static inline void timing_get(ticks* retval) { if ( clock_gettime( BEST_CLOCK_SOURCE, retval ) == -1 ) timing_abort(); retval->tv_sec -= basetime.tv_sec; } /** * Get a ticks instance somewhere in the future. * Useful for timeouts. */ static inline void timing_gets(ticks* retval, int32_t addSeconds) { timing_get( retval ); retval->tv_sec += addSeconds; } /** * Check whether given timeout is reached. * Might trigger up to one second early. */ static inline bool timing_reached(const ticks* timeout, const ticks* now) { return now->tv_sec >= timeout->tv_sec; } #define timing_1le2(one,two) timing_reached(one,two) /** * Precise check whether given timeout has been reached. */ static inline bool timing_reachedPrecise(const ticks* timeout, const ticks* now) { return now->tv_sec > timeout->tv_sec || (now->tv_sec == timeout->tv_sec && now->tv_nsec > timeout->tv_nsec); } /** * Shortcut for above. Useful if not used in loop. * Might trigger up to one second early. */ static inline bool timing_isReached(const ticks* timeout) { ticks now; timing_get( &now ); return timing_reached( timeout, &now ); } /** * Shortcut for above. Useful if not used in loop. */ static inline bool timing_isReachedPrecise(const ticks* timeout) { ticks now; timing_get( &now ); return timing_reachedPrecise( timeout, &now ); } /** * Get difference between two ticks, rounded down to seconds. * Make sure you pass the arguments in the proper order. If * end is before start, 0 will always be returned. */ static inline uint32_t timing_diff(const ticks *start, const ticks *end) { if ( end->tv_sec <= start->tv_sec ) return 0; return (uint32_t)( ( end->tv_sec - start->tv_sec ) + ( start->tv_nsec > end->tv_nsec ? -1 : 0 ) ); } /** * Get difference between two ticks, rounded down to milliseconds. * Same as above; passing arguments in reverse will always return 0. */ static inline uint64_t timing_diffMs(const ticks *start, const ticks *end) { if ( end->tv_sec < start->tv_sec ) return 0; uint64_t diff = (uint64_t)( end->tv_sec - start->tv_sec ) * 1000; if ( start->tv_nsec >= end->tv_nsec ) { if ( diff == 0 ) return 0; diff -= (start->tv_nsec - end->tv_nsec) / 1000000; } else { diff += (end->tv_nsec - start->tv_nsec) / 1000000; } return diff; } #endif