X-Git-Url: https://unix4lyfe.org/gitweb/darkstat-debian/blobdiff_plain/b6069b5cedf32ffb61978dba984fba393be6038a..53d9d497ad0dcb0c37efb23a5468762355db6512:/now.c diff --git a/now.c b/now.c new file mode 100644 index 0000000..f0751a8 --- /dev/null +++ b/now.c @@ -0,0 +1,152 @@ +/* darkstat 3 + * copyright (c) 2012 Emil Mikulic. + * + * now.c: a cache of the current time. + * + * Permission to use, copy, modify, and distribute this file for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "err.h" +#include "now.h" + +#include +#include +#include + +#ifdef __MACH__ +/* Fake up clock_gettime() on OS X. */ +# include +# include +# include +# include + +typedef int clockid_t; +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 + +static uint64_t mono_first = 0; + +int clock_gettime(clockid_t clk_id, struct timespec *tp) { + if (clk_id == CLOCK_REALTIME) { + struct timeval tv; + gettimeofday(&tv, NULL); + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = tv.tv_usec * 1000; + return 0; + } + if (clk_id == CLOCK_MONOTONIC) { + uint64_t t = mach_absolute_time(); + mach_timebase_info_data_t timebase; + mach_timebase_info(&timebase); + if (!mono_first) { + mono_first = t; + } + uint64_t tdiff = (t - mono_first) * timebase.numer / timebase.denom; + tp->tv_sec = tdiff / 1000000000; + tp->tv_nsec = tdiff % 1000000000; + return 0; + } + return -1; +} +#endif /* __MACH__ */ + +static struct timespec clock_real, clock_mono; +static int now_initialized = 0; + +long now_real(void) { + assert(now_initialized); + return clock_real.tv_sec; +} + +long now_mono(void) { + assert(now_initialized); + return clock_mono.tv_sec; +} + +static int before(const struct timespec *a, const struct timespec *b) { + if (a->tv_sec < b->tv_sec) + return 1; + if (a->tv_sec == b->tv_sec && a->tv_nsec < b->tv_nsec) + return 1; + return 0; +} + +static void clock_update(const clockid_t clk_id, + struct timespec *dest, + const char *name) { + struct timespec t; + + clock_gettime(clk_id, &t); + if (now_initialized && before(&t, dest)) { + verbosef("%s clock went backwards from %ld.%09ld to %ld.%09ld", + name, + (long)dest->tv_sec, + (long)dest->tv_nsec, + (long)t.tv_sec, + (long)t.tv_nsec); + } + memcpy(dest, &t, sizeof(t)); +} + +static void all_clocks_update(void) { + clock_update(CLOCK_REALTIME, &clock_real, "realtime"); + clock_update(CLOCK_MONOTONIC, &clock_mono, "monotonic"); +} + +void now_init(void) { + assert(!now_initialized); + all_clocks_update(); + now_initialized = 1; +} + +void now_update(void) { + assert(now_initialized); + all_clocks_update(); +} + +long mono_to_real(const long t) { + assert(now_initialized); + return t - clock_mono.tv_sec + clock_real.tv_sec; +} + +long real_to_mono(const long t) { + assert(now_initialized); + return t - clock_real.tv_sec + clock_mono.tv_sec; +} + +void timer_start(struct timespec *t) { + clock_gettime(CLOCK_MONOTONIC, t); +} + +static int64_t ts_diff(const struct timespec * const a, + const struct timespec * const b) { + return (int64_t)(a->tv_sec - b->tv_sec) * 1000000000 + + a->tv_nsec - b->tv_nsec; +} + +void timer_stop(const struct timespec * const t, + const int64_t nsec, + const char *warning) { + struct timespec t2; + int64_t diff; + + clock_gettime(CLOCK_MONOTONIC, &t2); + diff = ts_diff(&t2, t); + assert(diff > 0); + if (diff > nsec) + warnx("%s (took %lld nsec, over threshold of %lld nsec)", + warning, + (long long)diff, + (long long)nsec); +} + +/* vim:set ts=3 sw=3 tw=80 et: */