X-Git-Url: https://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftime%2Ftime.c;h=a6960335a50c814610ec1548a041644da4f81948;hp=5e36bf7b48dec210ac3f9341b9caee53b7164acb;hb=2a91b14cf2eea39b32d17a0ab14dd7243f36b79f;hpb=74257cee33ae3033f961d5f22a0313b8cb1b18d4 diff --git a/ccan/time/time.c b/ccan/time/time.c index 5e36bf7b..a6960335 100644 --- a/ccan/time/time.c +++ b/ccan/time/time.c @@ -1,108 +1,213 @@ /* Licensed under BSD-MIT - see LICENSE file for details */ #include #include -#include +#include -struct timeval time_now(void) +#ifdef DEBUG +#include +#define TIME_CHECK(t) time_check((t), __FILE__ ":" stringify(__LINE__)) +#else +#define TIME_CHECK(t) (t) +#endif + +#if !HAVE_CLOCK_GETTIME && !HAVE_CLOCK_GETTIME_IN_LIBRT +#include + +struct timespec time_now(void) { struct timeval now; + struct timespec ret; gettimeofday(&now, NULL); - return now; + ret.tv_sec = now.tv_sec; + ret.tv_nsec = now.tv_usec * 1000; + return TIME_CHECK(ret); +} +#else +#include +struct timespec time_now(void) +{ + struct timespec ret; + clock_gettime(CLOCK_REALTIME, &ret); + return TIME_CHECK(ret); } +#endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GETTIME_IN_LIBRT */ -bool time_greater(struct timeval a, struct timeval b) +bool time_greater(struct timespec a, struct timespec b) { - if (a.tv_sec > b.tv_sec) + if (TIME_CHECK(a).tv_sec > TIME_CHECK(b).tv_sec) return true; else if (a.tv_sec < b.tv_sec) return false; - return a.tv_usec > b.tv_usec; + return a.tv_nsec > b.tv_nsec; } -bool time_less(struct timeval a, struct timeval b) +bool time_less(struct timespec a, struct timespec b) { - if (a.tv_sec < b.tv_sec) + if (TIME_CHECK(a).tv_sec < TIME_CHECK(b).tv_sec) return true; else if (a.tv_sec > b.tv_sec) return false; - return a.tv_usec < b.tv_usec; + return a.tv_nsec < b.tv_nsec; } -bool time_eq(struct timeval a, struct timeval b) +bool time_eq(struct timespec a, struct timespec b) { - return a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec; + return TIME_CHECK(a).tv_sec == TIME_CHECK(b).tv_sec && a.tv_nsec == b.tv_nsec; } -struct timeval time_sub(struct timeval recent, struct timeval old) +struct timespec time_sub(struct timespec recent, struct timespec old) { - struct timeval diff; + struct timespec diff; - diff.tv_sec = recent.tv_sec - old.tv_sec; - if (old.tv_usec > recent.tv_usec) { + diff.tv_sec = TIME_CHECK(recent).tv_sec - TIME_CHECK(old).tv_sec; + if (old.tv_nsec > recent.tv_nsec) { diff.tv_sec--; - diff.tv_usec = 1000000 + recent.tv_usec - old.tv_usec; + diff.tv_nsec = 1000000000 + recent.tv_nsec - old.tv_nsec; } else - diff.tv_usec = recent.tv_usec - old.tv_usec; + diff.tv_nsec = recent.tv_nsec - old.tv_nsec; - assert(diff.tv_sec >= 0); - return diff; + return TIME_CHECK(diff); } -struct timeval time_add(struct timeval a, struct timeval b) +struct timespec time_add(struct timespec a, struct timespec b) { - struct timeval sum; + struct timespec sum; - sum.tv_sec = a.tv_sec + b.tv_sec; - sum.tv_usec = a.tv_usec + b.tv_usec; - if (sum.tv_usec > 1000000) { + sum.tv_sec = TIME_CHECK(a).tv_sec + TIME_CHECK(b).tv_sec; + sum.tv_nsec = a.tv_nsec + b.tv_nsec; + if (sum.tv_nsec >= 1000000000) { sum.tv_sec++; - sum.tv_usec -= 1000000; + sum.tv_nsec -= 1000000000; } - return sum; + return TIME_CHECK(sum); } -struct timeval time_divide(struct timeval t, unsigned long div) +struct timespec time_divide(struct timespec t, unsigned long div) { - return time_from_usec(time_to_usec(t) / div); + struct timespec res; + uint64_t rem, ns; + + /* Dividing seconds is simple. */ + res.tv_sec = TIME_CHECK(t).tv_sec / div; + rem = t.tv_sec % div; + + /* If we can't fit remainder * 1,000,000,000 in 64 bits? */ +#if 0 /* ilog is great, but we use fp for multiply anyway. */ + bits = ilog64(rem); + if (bits + 30 >= 64) { + /* Reduce accuracy slightly */ + rem >>= (bits - (64 - 30)); + div >>= (bits - (64 - 30)); + } +#endif + if (rem & ~(((uint64_t)1 << 30) - 1)) { + /* FIXME: fp is cheating! */ + double nsec = rem * 1000000000.0 + t.tv_nsec; + res.tv_nsec = nsec / div; + } else { + ns = rem * 1000000000 + t.tv_nsec; + res.tv_nsec = ns / div; + } + return TIME_CHECK(res); } -struct timeval time_multiply(struct timeval t, unsigned long mult) +struct timespec time_multiply(struct timespec t, unsigned long mult) { - return time_from_usec(time_to_usec(t) * mult); + struct timespec res; + + /* Are we going to overflow if we multiply nsec? */ + if (mult & ~((1UL << 30) - 1)) { + /* FIXME: fp is cheating! */ + double nsec = (double)t.tv_nsec * mult; + + res.tv_sec = nsec / 1000000000.0; + res.tv_nsec = nsec - (res.tv_sec * 1000000000.0); + } else { + uint64_t nsec = t.tv_nsec * mult; + + res.tv_nsec = nsec % 1000000000; + res.tv_sec = nsec / 1000000000; + } + res.tv_sec += TIME_CHECK(t).tv_sec * mult; + return TIME_CHECK(res); } -uint64_t time_to_msec(struct timeval t) +uint64_t time_to_msec(struct timespec t) { uint64_t msec; - msec = t.tv_usec / 1000 + (uint64_t)t.tv_sec * 1000; + msec = TIME_CHECK(t).tv_nsec / 1000000 + (uint64_t)t.tv_sec * 1000; return msec; } -uint64_t time_to_usec(struct timeval t) +uint64_t time_to_usec(struct timespec t) { uint64_t usec; - usec = t.tv_usec + (uint64_t)t.tv_sec * 1000000; + usec = TIME_CHECK(t).tv_nsec / 1000 + (uint64_t)t.tv_sec * 1000000; return usec; } -struct timeval time_from_msec(uint64_t msec) +uint64_t time_to_nsec(struct timespec t) { - struct timeval t; + uint64_t nsec; + + nsec = TIME_CHECK(t).tv_nsec + (uint64_t)t.tv_sec * 1000000000; + return nsec; +} - t.tv_usec = (msec % 1000) * 1000; +struct timespec time_from_msec(uint64_t msec) +{ + struct timespec t; + + t.tv_nsec = (msec % 1000) * 1000000; t.tv_sec = msec / 1000; - return t; + return TIME_CHECK(t); } -struct timeval time_from_usec(uint64_t usec) +struct timespec time_from_usec(uint64_t usec) { - struct timeval t; + struct timespec t; - t.tv_usec = usec % 1000000; + t.tv_nsec = (usec % 1000000) * 1000; t.tv_sec = usec / 1000000; + return TIME_CHECK(t); +} + +struct timespec time_from_nsec(uint64_t nsec) +{ + struct timespec t; + + t.tv_nsec = nsec % 1000000000; + t.tv_sec = nsec / 1000000000; + return TIME_CHECK(t); +} + +struct timespec time_check(struct timespec t, const char *abortstr) +{ + if (t.tv_sec < 0 || t.tv_nsec >= 1000000000) { + if (abortstr) { + fprintf(stderr, "%s: malformed time %li.%09li\n", + abortstr, + (long)t.tv_sec, (long)t.tv_nsec); + abort(); + } else { + struct timespec old = t; + + if (t.tv_nsec >= 1000000000) { + t.tv_sec += t.tv_nsec / 1000000000; + t.tv_nsec %= 1000000000; + } + if (t.tv_sec < 0) + t.tv_sec = 0; + + fprintf(stderr, "WARNING: malformed time" + " %li seconds %li ns converted to %li.%09li.\n", + (long)old.tv_sec, (long)old.tv_nsec, + (long)t.tv_sec, (long)t.tv_nsec); + } + } return t; }