C/Timers
From Attie's Wiki
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <stdint.h> #include <time.h> /* TIME_MAX should equate to 4294966999 this equals approx 49.71 days 4294966999 / 1000 / 60 / 60 / 24 = 49.71... */ #define SECONDS_MAX (((uint32_t)(((uint32_t)-1) / 1000) - 1)) /* roughly 49.7 days */ #define TIME_MAX ((uint32_t)((SECONDS_MAX * 1000) + 999)) /* roughly 48.7 days... 24 hours less than TIME_MAX */ #define TIMEOUT_MAX ((uint32_t)(TIME_MAX - (1000 * 60 * 60 * 24))) /* the difference between TIME_MAX and TIMEOUT_MAX allows a grace period of roughly 1 day for the user to check if a timeout has occured - if the user doesn't check within this time, then they deserve to have problems... :-) */ uint32_t get_time(void) { struct timespec ts; uint32_t ms; if (clock_gettime(CLOCK_BOOTTIME, &ts) == -1) { perror("clock_gettime()"); exit(1); } ts.tv_sec %= SECONDS_MAX; /* wrap the seconds field at SECONDS_MAX */ ts.tv_nsec /= 1000000; /* convert ns to ms */ ts.tv_sec += ts.tv_nsec / 1000; /* add any seconds from the nsec field - there shouldn't be any... */ ts.tv_nsec %= 1000; /* wrap the nsec field to 1 seconds-worth of milliseconds */ ts.tv_sec %= SECONDS_MAX; /* re-wrap the seconds field at SECONDS_MAX */ ms = ts.tv_sec * 1000; /* convert s to ms */ ms += ts.tv_nsec; /* add the ms count */ return ms; } uint32_t timeout_start(uint32_t timeout) { /* we need a 64-bit variable for this operation, because a large time + a large timeout could wrap at a funny place (32-bit max, not TIME_MAX) */ uint64_t ms; if (timeout > TIMEOUT_MAX) timeout = TIMEOUT_MAX; ms = get_time(); ms += timeout; ms %= TIME_MAX; return (uint32_t)(ms & 0xFFFFFFFF); } uint32_t timeout_remain(uint32_t timeout) { uint64_t to; uint32_t ms; to = timeout; ms = get_time(); if (to < ms) { /* a large time - a small timeout would cause the operation to wrap to a fumny place (32-bit max, not TIME_MAX), so we need to artificially wrap the calculation using a 64-bit variable */ to += TIME_MAX; } to -= ms; to %= TIME_MAX; ms = (uint32_t)(to & 0xFFFFFFFF); return (ms > TIMEOUT_MAX ? 0 : ms); } uint8_t timeout_check(uint32_t timeout) { return !timeout_remain(timeout); } /* - - - - */ int main(int argc, char *argv[]) { uint32_t ms; uint32_t timeout; printf( "t_max_sec : %10u\n", SECONDS_MAX); printf( "time_max : %10u\n", TIME_MAX); printf( "timeout_max : %10u\n", TIMEOUT_MAX); printf("\n"); timeout = timeout_start(15 * 1000); printf( "timeout : %10u\n", timeout); printf("\n"); for (;; printf("%c[4A", 27)) { ms = get_time(); printf("the time (in ms) : %10u (%.5f%%)%c[K\n", ms, (((float)ms / (float)TIME_MAX) * 100), 27); printf("timeout over? : %s%c[K\n", timeout_check(timeout) ? "yes" : "no", 27); printf("timeout remain : %10u%cK\n", timeout_remain(timeout), 27); { int x, y; uint32_t d, h, m, s, ss; x = 1; y = 1000; ss = (ms / x) % y; x *= y; y = 60; s = (ms / x) % y; x *= y; y = 60; m = (ms / x) % y; x *= y; y = 24; h = (ms / x) % y; x *= y; y = 50; d = (ms / x) % y; printf("time since boot : %ud, %02u:%02u:%02u.%03u%c[K\n", d, h, m, s, ss, 27); } fflush(stdout); usleep(1000); } return 0; }