From a097ddb4f5105d33146eb8f6afa7d6cd01d47fea Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 28 Jun 2018 12:57:01 -0400 Subject: Extract time functionality into lib/wallclock and lib/time --- src/common/compat.h | 43 +-- src/common/compat_time.c | 848 ------------------------------------------ src/common/compat_time.h | 232 ------------ src/common/include.am | 2 - src/common/util.c | 146 -------- src/common/util.h | 3 - src/include.am | 1 + src/lib/time/.may_include | 8 + src/lib/time/compat_time.c | 856 +++++++++++++++++++++++++++++++++++++++++++ src/lib/time/compat_time.h | 234 ++++++++++++ src/lib/time/include.am | 19 + src/lib/time/tvdiff.c | 155 ++++++++ src/lib/time/tvdiff.h | 16 + src/lib/wallclock/include.am | 1 + src/lib/wallclock/timeval.c | 0 src/lib/wallclock/timeval.h | 58 +++ src/or/circuitstats.c | 1 + src/or/circuituse.c | 1 + src/or/geoip.c | 1 + src/test/test_util.c | 1 + 20 files changed, 1353 insertions(+), 1273 deletions(-) delete mode 100644 src/common/compat_time.c delete mode 100644 src/common/compat_time.h create mode 100644 src/lib/time/.may_include create mode 100644 src/lib/time/compat_time.c create mode 100644 src/lib/time/compat_time.h create mode 100644 src/lib/time/include.am create mode 100644 src/lib/time/tvdiff.c create mode 100644 src/lib/time/tvdiff.h create mode 100644 src/lib/wallclock/timeval.c create mode 100644 src/lib/wallclock/timeval.h (limited to 'src') diff --git a/src/common/compat.h b/src/common/compat.h index 5cd8e72154..582945734c 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -59,54 +59,13 @@ #include "lib/fs/files.h" #include "lib/fs/mmap.h" #include "lib/fs/userdb.h" +#include "lib/wallclock/timeval.h" #include #include /* ===== Time compatibility */ -#ifndef timeradd -/** Replacement for timeradd on platforms that do not have it: sets tvout to - * the sum of tv1 and tv2. */ -#define timeradd(tv1,tv2,tvout) \ - do { \ - (tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \ - (tvout)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \ - if ((tvout)->tv_usec >= 1000000) { \ - (tvout)->tv_usec -= 1000000; \ - (tvout)->tv_sec++; \ - } \ - } while (0) -#endif /* !defined(timeradd) */ - -#ifndef timersub -/** Replacement for timersub on platforms that do not have it: sets tvout to - * tv1 minus tv2. */ -#define timersub(tv1,tv2,tvout) \ - do { \ - (tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec; \ - (tvout)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec; \ - if ((tvout)->tv_usec < 0) { \ - (tvout)->tv_usec += 1000000; \ - (tvout)->tv_sec--; \ - } \ - } while (0) -#endif /* !defined(timersub) */ - -#ifndef timercmp -/** Replacement for timercmp on platforms that do not have it: returns true - * iff the relational operator "op" makes the expression tv1 op tv2 true. - * - * Note that while this definition should work for all boolean operators, some - * platforms' native timercmp definitions do not support >=, <=, or ==. So - * don't use those. - */ -#define timercmp(tv1,tv2,op) \ - (((tv1)->tv_sec == (tv2)->tv_sec) ? \ - ((tv1)->tv_usec op (tv2)->tv_usec) : \ - ((tv1)->tv_sec op (tv2)->tv_sec)) -#endif /* !defined(timercmp) */ - /* ===== File compatibility */ /* ===== Net compatibility */ diff --git a/src/common/compat_time.c b/src/common/compat_time.c deleted file mode 100644 index 148f2f8957..0000000000 --- a/src/common/compat_time.c +++ /dev/null @@ -1,848 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat_time.c - * \brief Portable wrappers for finding out the current time, running - * timers, etc. - **/ - -#define COMPAT_TIME_PRIVATE -#include "common/compat.h" - -#ifdef _WIN32 -#include -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef TOR_UNIT_TESTS -#if !defined(HAVE_USLEEP) && defined(HAVE_SYS_SELECT_H) -/* as fallback implementation for tor_sleep_msec */ -#include -#endif -#endif /* defined(TOR_UNIT_TESTS) */ - -#ifdef __APPLE__ -#include -#endif - -#include "lib/err/torerr.h" -#include "lib/log/torlog.h" -#include "common/util.h" - -#ifdef _WIN32 -#undef HAVE_CLOCK_GETTIME -#endif - -#ifdef TOR_UNIT_TESTS -/** Delay for msec milliseconds. Only used in tests. */ -void -tor_sleep_msec(int msec) -{ -#ifdef _WIN32 - Sleep(msec); -#elif defined(HAVE_USLEEP) - sleep(msec / 1000); - /* Some usleep()s hate sleeping more than 1 sec */ - usleep((msec % 1000) * 1000); -#elif defined(HAVE_SYS_SELECT_H) - struct timeval tv = { msec / 1000, (msec % 1000) * 1000}; - select(0, NULL, NULL, NULL, &tv); -#else - sleep(CEIL_DIV(msec, 1000)); -#endif /* defined(_WIN32) || ... */ -} -#endif /* defined(TOR_UNIT_TESTS) */ - -#define ONE_MILLION ((int64_t) (1000 * 1000)) -#define ONE_BILLION ((int64_t) (1000 * 1000 * 1000)) - -/** True iff monotime_init has been called. */ -static int monotime_initialized = 0; - -static monotime_t initialized_at; -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT -static monotime_coarse_t initialized_at_coarse; -#endif - -#ifdef TOR_UNIT_TESTS -/** True if we are running unit tests and overriding the current monotonic - * time. Note that mocked monotonic time might not be monotonic. - */ -static int monotime_mocking_enabled = 0; -static monotime_t initialized_at_saved; - -static int64_t mock_time_nsec = 0; -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT -static int64_t mock_time_nsec_coarse = 0; -static monotime_coarse_t initialized_at_coarse_saved; -#endif - -void -monotime_enable_test_mocking(void) -{ - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - - tor_assert_nonfatal(monotime_mocking_enabled == 0); - monotime_mocking_enabled = 1; - memcpy(&initialized_at_saved, - &initialized_at, sizeof(monotime_t)); - memset(&initialized_at, 0, sizeof(monotime_t)); -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT - memcpy(&initialized_at_coarse_saved, - &initialized_at_coarse, sizeof(monotime_coarse_t)); - memset(&initialized_at_coarse, 0, sizeof(monotime_coarse_t)); -#endif -} - -void -monotime_disable_test_mocking(void) -{ - tor_assert_nonfatal(monotime_mocking_enabled == 1); - monotime_mocking_enabled = 0; - - memcpy(&initialized_at, - &initialized_at_saved, sizeof(monotime_t)); -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT - memcpy(&initialized_at_coarse, - &initialized_at_coarse_saved, sizeof(monotime_coarse_t)); -#endif -} - -void -monotime_set_mock_time_nsec(int64_t nsec) -{ - tor_assert_nonfatal(monotime_mocking_enabled == 1); - mock_time_nsec = nsec; -} - -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT -void -monotime_coarse_set_mock_time_nsec(int64_t nsec) -{ - tor_assert_nonfatal(monotime_mocking_enabled == 1); - mock_time_nsec_coarse = nsec; -} -#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ -#endif /* defined(TOR_UNIT_TESTS) */ - -/* "ratchet" functions for monotonic time. */ - -#if defined(_WIN32) || defined(TOR_UNIT_TESTS) - -/** Protected by lock: last value returned by monotime_get(). */ -static int64_t last_pctr = 0; -/** Protected by lock: offset we must add to monotonic time values. */ -static int64_t pctr_offset = 0; -/* If we are using GetTickCount(), how many times has it rolled over? */ -static uint32_t rollover_count = 0; -/* If we are using GetTickCount(), what's the last value it returned? */ -static int64_t last_tick_count = 0; - -/** Helper for windows: Called with a sequence of times that are supposed - * to be monotonic; increments them as appropriate so that they actually - * _are_ monotonic. - * - * Caller must hold lock. */ -STATIC int64_t -ratchet_performance_counter(int64_t count_raw) -{ - /* must hold lock */ - const int64_t count_adjusted = count_raw + pctr_offset; - - if (PREDICT_UNLIKELY(count_adjusted < last_pctr)) { - /* Monotonicity failed! Pretend no time elapsed. */ - pctr_offset = last_pctr - count_raw; - return last_pctr; - } else { - last_pctr = count_adjusted; - return count_adjusted; - } -} - -STATIC int64_t -ratchet_coarse_performance_counter(const int64_t count_raw) -{ - int64_t count = count_raw + (((int64_t)rollover_count) << 32); - while (PREDICT_UNLIKELY(count < last_tick_count)) { - ++rollover_count; - count = count_raw + (((int64_t)rollover_count) << 32); - } - last_tick_count = count; - return count; -} -#endif /* defined(_WIN32) || defined(TOR_UNIT_TESTS) */ - -#if defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) -static struct timeval last_timeofday = { 0, 0 }; -static struct timeval timeofday_offset = { 0, 0 }; - -/** Helper for gettimeofday(): Called with a sequence of times that are - * supposed to be monotonic; increments them as appropriate so that they - * actually _are_ monotonic. - * - * Caller must hold lock. */ -STATIC void -ratchet_timeval(const struct timeval *timeval_raw, struct timeval *out) -{ - /* must hold lock */ - timeradd(timeval_raw, &timeofday_offset, out); - if (PREDICT_UNLIKELY(timercmp(out, &last_timeofday, OP_LT))) { - /* time ran backwards. Instead, declare that no time occurred. */ - timersub(&last_timeofday, timeval_raw, &timeofday_offset); - memcpy(out, &last_timeofday, sizeof(struct timeval)); - } else { - memcpy(&last_timeofday, out, sizeof(struct timeval)); - } -} -#endif /* defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) */ - -#ifdef TOR_UNIT_TESTS -/** For testing: reset all the ratchets */ -void -monotime_reset_ratchets_for_testing(void) -{ - last_pctr = pctr_offset = last_tick_count = 0; - rollover_count = 0; - memset(&last_timeofday, 0, sizeof(struct timeval)); - memset(&timeofday_offset, 0, sizeof(struct timeval)); -} -#endif /* defined(TOR_UNIT_TESTS) */ - -#ifdef __APPLE__ - -/** Initialized on startup: tells is how to convert from ticks to - * nanoseconds. - */ -static struct mach_timebase_info mach_time_info; -static struct mach_timebase_info mach_time_info_msec_cvt; -static int monotime_shift = 0; - -static void -monotime_init_internal(void) -{ - tor_assert(!monotime_initialized); - int r = mach_timebase_info(&mach_time_info); - tor_assert(r == 0); - tor_assert(mach_time_info.denom != 0); - - { - // approximate only. - uint64_t ns_per_tick = mach_time_info.numer / mach_time_info.denom; - uint64_t ms_per_tick = ns_per_tick * ONE_MILLION; - // requires that tor_log2(0) == 0. - monotime_shift = tor_log2(ms_per_tick); - } - { - // For converting ticks to milliseconds in a 32-bit-friendly way, we - // will first right-shift by 20, and then multiply by 20/19, since - // (1<<20) * 19/20 is about 1e6. We precompute a new numerate and - // denominator here to avoid multiple multiplies. - mach_time_info_msec_cvt.numer = mach_time_info.numer * 20; - mach_time_info_msec_cvt.denom = mach_time_info.denom * 19; - } -} - -/** - * Set "out" to the most recent monotonic time value - */ -void -monotime_get(monotime_t *out) -{ -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->abstime_ = (mock_time_nsec * mach_time_info.denom) - / mach_time_info.numer; - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - out->abstime_ = mach_absolute_time(); -} - -#if defined(HAVE_MACH_APPROXIMATE_TIME) -void -monotime_coarse_get(monotime_coarse_t *out) -{ -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->abstime_ = (mock_time_nsec_coarse * mach_time_info.denom) - / mach_time_info.numer; - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - out->abstime_ = mach_approximate_time(); -} -#endif - -/** - * Return the number of nanoseconds between start and end. - */ -int64_t -monotime_diff_nsec(const monotime_t *start, - const monotime_t *end) -{ - if (BUG(mach_time_info.denom == 0)) { - monotime_init(); - } - const int64_t diff_ticks = end->abstime_ - start->abstime_; - const int64_t diff_nsec = - (diff_ticks * mach_time_info.numer) / mach_time_info.denom; - return diff_nsec; -} - -int32_t -monotime_coarse_diff_msec32_(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - if (BUG(mach_time_info.denom == 0)) { - monotime_init(); - } - const int64_t diff_ticks = end->abstime_ - start->abstime_; - - /* We already require in di_ops.c that right-shift performs a sign-extend. */ - const int32_t diff_microticks = (int32_t)(diff_ticks >> 20); - - return (diff_microticks * mach_time_info_msec_cvt.numer) / - mach_time_info_msec_cvt.denom; -} - -uint32_t -monotime_coarse_to_stamp(const monotime_coarse_t *t) -{ - return (uint32_t)(t->abstime_ >> monotime_shift); -} - -int -monotime_is_zero(const monotime_t *val) -{ - return val->abstime_ == 0; -} - -void -monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) -{ - const uint64_t nsec = msec * ONE_MILLION; - const uint64_t ticks = (nsec * mach_time_info.denom) / mach_time_info.numer; - out->abstime_ = val->abstime_ + ticks; -} - -/* end of "__APPLE__" */ -#elif defined(HAVE_CLOCK_GETTIME) - -#ifdef CLOCK_MONOTONIC_COARSE -/** - * Which clock should we use for coarse-grained monotonic time? By default - * this is CLOCK_MONOTONIC_COARSE, but it might not work -- for example, - * if we're compiled with newer Linux headers and then we try to run on - * an old Linux kernel. In that case, we will fall back to CLOCK_MONOTONIC. - */ -static int clock_monotonic_coarse = CLOCK_MONOTONIC_COARSE; -#endif /* defined(CLOCK_MONOTONIC_COARSE) */ - -static void -monotime_init_internal(void) -{ -#ifdef CLOCK_MONOTONIC_COARSE - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) < 0) { - log_info(LD_GENERAL, "CLOCK_MONOTONIC_COARSE isn't working (%s); " - "falling back to CLOCK_MONOTONIC.", strerror(errno)); - clock_monotonic_coarse = CLOCK_MONOTONIC; - } -#endif /* defined(CLOCK_MONOTONIC_COARSE) */ -} - -void -monotime_get(monotime_t *out) -{ -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->ts_.tv_sec = (time_t) (mock_time_nsec / ONE_BILLION); - out->ts_.tv_nsec = (int) (mock_time_nsec % ONE_BILLION); - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - int r = clock_gettime(CLOCK_MONOTONIC, &out->ts_); - tor_assert(r == 0); -} - -#ifdef CLOCK_MONOTONIC_COARSE -void -monotime_coarse_get(monotime_coarse_t *out) -{ -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->ts_.tv_sec = (time_t) (mock_time_nsec_coarse / ONE_BILLION); - out->ts_.tv_nsec = (int) (mock_time_nsec_coarse % ONE_BILLION); - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - int r = clock_gettime(clock_monotonic_coarse, &out->ts_); - if (PREDICT_UNLIKELY(r < 0) && - errno == EINVAL && - clock_monotonic_coarse == CLOCK_MONOTONIC_COARSE) { - /* We should have caught this at startup in monotime_init_internal! - */ - log_warn(LD_BUG, "Falling back to non-coarse monotonic time %s initial " - "system start?", monotime_initialized?"after":"without"); - clock_monotonic_coarse = CLOCK_MONOTONIC; - r = clock_gettime(clock_monotonic_coarse, &out->ts_); - } - - tor_assert(r == 0); -} -#endif /* defined(CLOCK_MONOTONIC_COARSE) */ - -int64_t -monotime_diff_nsec(const monotime_t *start, - const monotime_t *end) -{ - const int64_t diff_sec = end->ts_.tv_sec - start->ts_.tv_sec; - const int64_t diff_nsec = diff_sec * ONE_BILLION + - (end->ts_.tv_nsec - start->ts_.tv_nsec); - - return diff_nsec; -} - -int32_t -monotime_coarse_diff_msec32_(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - const int32_t diff_sec = (int32_t)(end->ts_.tv_sec - start->ts_.tv_sec); - const int32_t diff_nsec = (int32_t)(end->ts_.tv_nsec - start->ts_.tv_nsec); - return diff_sec * 1000 + diff_nsec / ONE_MILLION; -} - -/* This value is ONE_BILLION >> 20. */ -static const uint32_t STAMP_TICKS_PER_SECOND = 953; - -uint32_t -monotime_coarse_to_stamp(const monotime_coarse_t *t) -{ - uint32_t nsec = (uint32_t)t->ts_.tv_nsec; - uint32_t sec = (uint32_t)t->ts_.tv_sec; - - return (sec * STAMP_TICKS_PER_SECOND) + (nsec >> 20); -} - -int -monotime_is_zero(const monotime_t *val) -{ - return val->ts_.tv_sec == 0 && val->ts_.tv_nsec == 0; -} - -void -monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) -{ - const uint32_t sec = msec / 1000; - const uint32_t msec_remainder = msec % 1000; - out->ts_.tv_sec = val->ts_.tv_sec + sec; - out->ts_.tv_nsec = val->ts_.tv_nsec + (msec_remainder * ONE_MILLION); - if (out->ts_.tv_nsec > ONE_BILLION) { - out->ts_.tv_nsec -= ONE_BILLION; - out->ts_.tv_sec += 1; - } -} - -/* end of "HAVE_CLOCK_GETTIME" */ -#elif defined (_WIN32) - -/** Result of QueryPerformanceFrequency, in terms needed to - * convert ticks to nanoseconds. */ -static int64_t nsec_per_tick_numer = 1; -static int64_t nsec_per_tick_denom = 1; - -/** Lock to protect last_pctr and pctr_offset */ -static CRITICAL_SECTION monotime_lock; -/** Lock to protect rollover_count and last_tick_count */ -static CRITICAL_SECTION monotime_coarse_lock; - -typedef ULONGLONG (WINAPI *GetTickCount64_fn_t)(void); -static GetTickCount64_fn_t GetTickCount64_fn = NULL; - -static void -monotime_init_internal(void) -{ - tor_assert(!monotime_initialized); - BOOL ok = InitializeCriticalSectionAndSpinCount(&monotime_lock, 200); - tor_assert(ok); - ok = InitializeCriticalSectionAndSpinCount(&monotime_coarse_lock, 200); - tor_assert(ok); - LARGE_INTEGER li; - ok = QueryPerformanceFrequency(&li); - tor_assert(ok); - tor_assert(li.QuadPart); - - uint64_t n = ONE_BILLION; - uint64_t d = li.QuadPart; - /* We need to simplify this or we'll probably overflow the int64. */ - simplify_fraction64(&n, &d); - tor_assert(n <= INT64_MAX); - tor_assert(d <= INT64_MAX); - - nsec_per_tick_numer = (int64_t) n; - nsec_per_tick_denom = (int64_t) d; - - last_pctr = 0; - pctr_offset = 0; - - HANDLE h = load_windows_system_library(TEXT("kernel32.dll")); - if (h) { - GetTickCount64_fn = (GetTickCount64_fn_t) - GetProcAddress(h, "GetTickCount64"); - } - // FreeLibrary(h) ? -} - -void -monotime_get(monotime_t *out) -{ - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->pcount_ = (mock_time_nsec * nsec_per_tick_denom) - / nsec_per_tick_numer; - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - - /* Alas, QueryPerformanceCounter is not always monotonic: see bug list at - - https://www.python.org/dev/peps/pep-0418/#windows-queryperformancecounter - */ - - EnterCriticalSection(&monotime_lock); - LARGE_INTEGER res; - BOOL ok = QueryPerformanceCounter(&res); - tor_assert(ok); - const int64_t count_raw = res.QuadPart; - out->pcount_ = ratchet_performance_counter(count_raw); - LeaveCriticalSection(&monotime_lock); -} - -void -monotime_coarse_get(monotime_coarse_t *out) -{ -#ifdef TOR_UNIT_TESTS - if (monotime_mocking_enabled) { - out->tick_count_ = mock_time_nsec_coarse / ONE_MILLION; - return; - } -#endif /* defined(TOR_UNIT_TESTS) */ - - if (GetTickCount64_fn) { - out->tick_count_ = (int64_t)GetTickCount64_fn(); - } else { - EnterCriticalSection(&monotime_coarse_lock); - DWORD tick = GetTickCount(); - out->tick_count_ = ratchet_coarse_performance_counter(tick); - LeaveCriticalSection(&monotime_coarse_lock); - } -} - -int64_t -monotime_diff_nsec(const monotime_t *start, - const monotime_t *end) -{ - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - const int64_t diff_ticks = end->pcount_ - start->pcount_; - return (diff_ticks * nsec_per_tick_numer) / nsec_per_tick_denom; -} - -int64_t -monotime_coarse_diff_msec(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - const int64_t diff_ticks = end->tick_count_ - start->tick_count_; - return diff_ticks; -} - -int32_t -monotime_coarse_diff_msec32_(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - return (int32_t)monotime_coarse_diff_msec(start, end); -} - -int64_t -monotime_coarse_diff_usec(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - return monotime_coarse_diff_msec(start, end) * 1000; -} - -int64_t -monotime_coarse_diff_nsec(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - return monotime_coarse_diff_msec(start, end) * ONE_MILLION; -} - -static const uint32_t STAMP_TICKS_PER_SECOND = 1000; - -uint32_t -monotime_coarse_to_stamp(const monotime_coarse_t *t) -{ - return (uint32_t) t->tick_count_; -} - -int -monotime_is_zero(const monotime_t *val) -{ - return val->pcount_ == 0; -} - -int -monotime_coarse_is_zero(const monotime_coarse_t *val) -{ - return val->tick_count_ == 0; -} - -void -monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) -{ - const uint64_t nsec = msec * ONE_MILLION; - const uint64_t ticks = (nsec * nsec_per_tick_denom) / nsec_per_tick_numer; - out->pcount_ = val->pcount_ + ticks; -} - -void -monotime_coarse_add_msec(monotime_coarse_t *out, const monotime_coarse_t *val, - uint32_t msec) -{ - out->tick_count_ = val->tick_count_ + msec; -} - -/* end of "_WIN32" */ -#elif defined(MONOTIME_USING_GETTIMEOFDAY) - -static tor_mutex_t monotime_lock; - -/** Initialize the monotonic timer subsystem. */ -static void -monotime_init_internal(void) -{ - tor_assert(!monotime_initialized); - tor_mutex_init(&monotime_lock); -} - -void -monotime_get(monotime_t *out) -{ - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - - tor_mutex_acquire(&monotime_lock); - struct timeval timeval_raw; - tor_gettimeofday(&timeval_raw); - ratchet_timeval(&timeval_raw, &out->tv_); - tor_mutex_release(&monotime_lock); -} - -int64_t -monotime_diff_nsec(const monotime_t *start, - const monotime_t *end) -{ - struct timeval diff; - timersub(&end->tv_, &start->tv_, &diff); - return (diff.tv_sec * ONE_BILLION + diff.tv_usec * 1000); -} - -int32_t -monotime_coarse_diff_msec32_(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ - struct timeval diff; - timersub(&end->tv_, &start->tv_, &diff); - return diff.tv_sec * 1000 + diff.tv_usec / 1000; -} - -/* This value is ONE_MILLION >> 10. */ -static const uint32_t STAMP_TICKS_PER_SECOND = 976; - -uint32_t -monotime_coarse_to_stamp(const monotime_coarse_t *t) -{ - const uint32_t usec = (uint32_t)t->tv_.tv_usec; - const uint32_t sec = (uint32_t)t->tv_.tv_sec; - return (sec * STAMP_TICKS_PER_SECOND) | (nsec >> 10); -} - -int -monotime_is_zero(const monotime_t *val) -{ - return val->tv_.tv_sec == 0 && val->tv_.tv_usec == 0; -} - -void -monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) -{ - const uint32_t sec = msec / 1000; - const uint32_t msec_remainder = msec % 1000; - out->tv_.tv_sec = val->tv_.tv_sec + sec; - out->tv_.tv_usec = val->tv_.tv_nsec + (msec_remainder * 1000); - if (out->tv_.tv_usec > ONE_MILLION) { - out->tv_.tv_usec -= ONE_MILLION; - out->tv_.tv_sec += 1; - } -} - -/* end of "MONOTIME_USING_GETTIMEOFDAY" */ -#else -#error "No way to implement monotonic timers." -#endif /* defined(__APPLE__) || ... */ - -/** - * Initialize the monotonic timer subsystem. Must be called before any - * monotonic timer functions. This function is idempotent. - */ -void -monotime_init(void) -{ - if (!monotime_initialized) { - monotime_init_internal(); - monotime_initialized = 1; - monotime_get(&initialized_at); -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT - monotime_coarse_get(&initialized_at_coarse); -#endif - } -} - -void -monotime_zero(monotime_t *out) -{ - memset(out, 0, sizeof(*out)); -} -#ifdef MONOTIME_COARSE_TYPE_IS_DIFFERENT -void -monotime_coarse_zero(monotime_coarse_t *out) -{ - memset(out, 0, sizeof(*out)); -} -#endif - -int64_t -monotime_diff_usec(const monotime_t *start, - const monotime_t *end) -{ - const int64_t nsec = monotime_diff_nsec(start, end); - return CEIL_DIV(nsec, 1000); -} - -int64_t -monotime_diff_msec(const monotime_t *start, - const monotime_t *end) -{ - const int64_t nsec = monotime_diff_nsec(start, end); - return CEIL_DIV(nsec, ONE_MILLION); -} - -uint64_t -monotime_absolute_nsec(void) -{ - monotime_t now; - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - - monotime_get(&now); - return monotime_diff_nsec(&initialized_at, &now); -} - -uint64_t -monotime_absolute_usec(void) -{ - return monotime_absolute_nsec() / 1000; -} - -uint64_t -monotime_absolute_msec(void) -{ - return monotime_absolute_nsec() / ONE_MILLION; -} - -#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT -uint64_t -monotime_coarse_absolute_nsec(void) -{ - if (BUG(monotime_initialized == 0)) { - monotime_init(); - } - - monotime_coarse_t now; - monotime_coarse_get(&now); - return monotime_coarse_diff_nsec(&initialized_at_coarse, &now); -} - -uint64_t -monotime_coarse_absolute_usec(void) -{ - return monotime_coarse_absolute_nsec() / 1000; -} - -uint64_t -monotime_coarse_absolute_msec(void) -{ - return monotime_coarse_absolute_nsec() / ONE_MILLION; -} -#else -#define initialized_at_coarse initialized_at -#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ - -/** - * Return the current time "stamp" as described by monotime_coarse_to_stamp. - */ -uint32_t -monotime_coarse_get_stamp(void) -{ - monotime_coarse_t now; - monotime_coarse_get(&now); - return monotime_coarse_to_stamp(&now); -} - -#ifdef __APPLE__ -uint64_t -monotime_coarse_stamp_units_to_approx_msec(uint64_t units) -{ - /* Recover as much precision as we can. */ - uint64_t abstime_diff = (units << monotime_shift); - return (abstime_diff * mach_time_info.numer) / - (mach_time_info.denom * ONE_MILLION); -} -uint64_t -monotime_msec_to_approx_coarse_stamp_units(uint64_t msec) -{ - uint64_t abstime_val = - (((uint64_t)msec) * ONE_MILLION * mach_time_info.denom) / - mach_time_info.numer; - return abstime_val >> monotime_shift; -} -#else -uint64_t -monotime_coarse_stamp_units_to_approx_msec(uint64_t units) -{ - return (units * 1000) / STAMP_TICKS_PER_SECOND; -} -uint64_t -monotime_msec_to_approx_coarse_stamp_units(uint64_t msec) -{ - return (msec * STAMP_TICKS_PER_SECOND) / 1000; -} -#endif diff --git a/src/common/compat_time.h b/src/common/compat_time.h deleted file mode 100644 index 2f7e87a633..0000000000 --- a/src/common/compat_time.h +++ /dev/null @@ -1,232 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat_time.h - * - * \brief Functions and types for monotonic times. - * - * monotime_* functions try to provide a high-resolution monotonic timer with - * something the best resolution the system provides. monotime_coarse_* - * functions run faster (if the operating system gives us a way to do that) - * but produce a less accurate timer: accuracy will probably be on the order - * of tens of milliseconds. - */ - -#ifndef TOR_COMPAT_TIME_H -#define TOR_COMPAT_TIME_H - -#include "orconfig.h" -#include "lib/wallclock/tor_gettimeofday.h" - -#ifdef _WIN32 -#undef HAVE_CLOCK_GETTIME -#endif - -#if defined(HAVE_CLOCK_GETTIME) -/* to ensure definition of CLOCK_MONOTONIC_COARSE if it's there */ -#include -#endif - -#if !defined(HAVE_STRUCT_TIMEVAL_TV_SEC) -/** Implementation of timeval for platforms that don't have it. */ -struct timeval { - time_t tv_sec; - unsigned int tv_usec; -}; -#endif /* !defined(HAVE_STRUCT_TIMEVAL_TV_SEC) */ - -/** Represents a monotonic timer in a platform-dependent way. */ -typedef struct monotime_t { -#ifdef __APPLE__ - /* On apple, there is a 64-bit counter whose precision we must look up. */ - uint64_t abstime_; -#elif defined(HAVE_CLOCK_GETTIME) - /* It sure would be nice to use clock_gettime(). Posix is a nice thing. */ - struct timespec ts_; -#elif defined (_WIN32) - /* On Windows, there is a 64-bit counter whose precision we must look up. */ - int64_t pcount_; -#else -#define MONOTIME_USING_GETTIMEOFDAY - /* Otherwise, we will be stuck using gettimeofday. */ - struct timeval tv_; -#endif /* defined(__APPLE__) || ... */ -} monotime_t; - -#if defined(CLOCK_MONOTONIC_COARSE) && \ - defined(HAVE_CLOCK_GETTIME) -#define MONOTIME_COARSE_FN_IS_DIFFERENT -#define monotime_coarse_t monotime_t -#elif defined(_WIN32) -#define MONOTIME_COARSE_FN_IS_DIFFERENT -#define MONOTIME_COARSE_TYPE_IS_DIFFERENT -/** Represents a coarse monotonic time in a platform-independent way. */ -typedef struct monotime_coarse_t { - uint64_t tick_count_; -} monotime_coarse_t; -#elif defined(__APPLE__) && defined(HAVE_MACH_APPROXIMATE_TIME) -#define MONOTIME_COARSE_FN_IS_DIFFERENT -#define monotime_coarse_t monotime_t -#else -#define monotime_coarse_t monotime_t -#endif /* defined(CLOCK_MONOTONIC_COARSE) && ... || ... */ - -/** - * Initialize the timing subsystem. This function is idempotent. - */ -void monotime_init(void); -/** - * Set out to the current time. - */ -void monotime_get(monotime_t *out); -/** - * Return the number of nanoseconds between start and end. - */ -int64_t monotime_diff_nsec(const monotime_t *start, const monotime_t *end); -/** - * Return the number of microseconds between start and end. - */ -int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end); -/** - * Return the number of milliseconds between start and end. - */ -int64_t monotime_diff_msec(const monotime_t *start, const monotime_t *end); -/** - * Return the number of nanoseconds since the timer system was initialized. - */ -uint64_t monotime_absolute_nsec(void); -/** - * Return the number of microseconds since the timer system was initialized. - */ -uint64_t monotime_absolute_usec(void); -/** - * Return the number of milliseconds since the timer system was initialized. - */ -uint64_t monotime_absolute_msec(void); - -/** - * Set out to zero. - */ -void monotime_zero(monotime_t *out); -/** - * Return true iff out is zero - */ -int monotime_is_zero(const monotime_t *out); - -/** - * Set out to N milliseconds after val. - */ -/* XXXX We should add a more generic function here if we ever need to */ -void monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec); - -#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT) -/** - * Set out to the current coarse time. - */ -void monotime_coarse_get(monotime_coarse_t *out); -uint64_t monotime_coarse_absolute_nsec(void); -uint64_t monotime_coarse_absolute_usec(void); -uint64_t monotime_coarse_absolute_msec(void); -#else /* !(defined(MONOTIME_COARSE_FN_IS_DIFFERENT)) */ -#define monotime_coarse_get monotime_get -#define monotime_coarse_absolute_nsec monotime_absolute_nsec -#define monotime_coarse_absolute_usec monotime_absolute_usec -#define monotime_coarse_absolute_msec monotime_absolute_msec -#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ - -/** - * Return a "timestamp" approximation for a coarse monotonic timer. - * This timestamp is meant to be fast to calculate and easy to - * compare, and have a unit of something roughly around 1 msec. - * - * It will wrap over from time to time. - * - * It has no defined zero point. - */ -uint32_t monotime_coarse_to_stamp(const monotime_coarse_t *t); -/** - * Convert a difference, expressed in the units of monotime_coarse_to_stamp, - * into an approximate number of milliseconds. - */ -uint64_t monotime_coarse_stamp_units_to_approx_msec(uint64_t units); -uint64_t monotime_msec_to_approx_coarse_stamp_units(uint64_t msec); -uint32_t monotime_coarse_get_stamp(void); - -#if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) -int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start, - const monotime_coarse_t *end); -int64_t monotime_coarse_diff_usec(const monotime_coarse_t *start, - const monotime_coarse_t *end); -int64_t monotime_coarse_diff_msec(const monotime_coarse_t *start, - const monotime_coarse_t *end); -void monotime_coarse_zero(monotime_coarse_t *out); -int monotime_coarse_is_zero(const monotime_coarse_t *val); -void monotime_coarse_add_msec(monotime_coarse_t *out, - const monotime_coarse_t *val, uint32_t msec); -#else /* !(defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT)) */ -#define monotime_coarse_diff_nsec monotime_diff_nsec -#define monotime_coarse_diff_usec monotime_diff_usec -#define monotime_coarse_diff_msec monotime_diff_msec -#define monotime_coarse_zero monotime_zero -#define monotime_coarse_is_zero monotime_is_zero -#define monotime_coarse_add_msec monotime_add_msec -#endif /* defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) */ - -/** - * As monotime_coarse_diff_msec, but avoid 64-bit division. - * - * Requires that the difference fit into an int32_t; not for use with - * large time differences. - */ -int32_t monotime_coarse_diff_msec32_(const monotime_coarse_t *start, - const monotime_coarse_t *end); - -/** - * As monotime_coarse_diff_msec, but avoid 64-bit division if it is expensive. - * - * Requires that the difference fit into an int32_t; not for use with - * large time differences. - */ -static inline int32_t -monotime_coarse_diff_msec32(const monotime_coarse_t *start, - const monotime_coarse_t *end) -{ -#if SIZEOF_VOID_P == 8 - // on a 64-bit platform, let's assume 64/64 division is cheap. - return (int32_t) monotime_coarse_diff_msec(start, end); -#else - return monotime_coarse_diff_msec32_(start, end); -#endif -} - -#ifdef TOR_UNIT_TESTS -void tor_sleep_msec(int msec); - -void monotime_enable_test_mocking(void); -void monotime_disable_test_mocking(void); -void monotime_set_mock_time_nsec(int64_t); -#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT) -void monotime_coarse_set_mock_time_nsec(int64_t); -#else -#define monotime_coarse_set_mock_time_nsec monotime_set_mock_time_nsec -#endif -#endif /* defined(TOR_UNIT_TESTS) */ - -#ifdef COMPAT_TIME_PRIVATE -#if defined(_WIN32) || defined(TOR_UNIT_TESTS) -STATIC int64_t ratchet_performance_counter(int64_t count_raw); -STATIC int64_t ratchet_coarse_performance_counter(int64_t count_raw); -#endif -#if defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) -STATIC void ratchet_timeval(const struct timeval *timeval_raw, - struct timeval *out); -#endif -#ifdef TOR_UNIT_TESTS -void monotime_reset_ratchets_for_testing(void); -#endif -#endif /* defined(COMPAT_TIME_PRIVATE) */ - -#endif /* !defined(TOR_COMPAT_TIME_H) */ diff --git a/src/common/include.am b/src/common/include.am index 2d7297665c..bb1a3ee420 100644 --- a/src/common/include.am +++ b/src/common/include.am @@ -27,7 +27,6 @@ LIBOR_A_SRC = \ src/common/address_set.c \ src/common/buffers.c \ src/common/compat.c \ - src/common/compat_time.c \ src/common/util.c \ src/common/token_bucket.c \ src/common/workqueue.c \ @@ -64,7 +63,6 @@ COMMONHEADERS = \ src/common/buffers.h \ src/common/compat.h \ src/common/compat_libevent.h \ - src/common/compat_time.h \ src/common/handles.h \ src/common/procmon.h \ src/common/timers.h \ diff --git a/src/common/util.c b/src/common/util.c index e1fae0deab..b31bb834e1 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -135,152 +135,6 @@ ENABLE_GCC_WARNING(aggregate-return) * Time * ===== */ -#define TOR_USEC_PER_SEC 1000000 - -/** Return the difference between start->tv_sec and end->tv_sec. - * Returns INT64_MAX on overflow and underflow. - */ -static int64_t -tv_secdiff_impl(const struct timeval *start, const struct timeval *end) -{ - const int64_t s = (int64_t)start->tv_sec; - const int64_t e = (int64_t)end->tv_sec; - - /* This may not be the most efficient way of implemeting this check, - * but it's easy to see that it's correct and doesn't overflow */ - - if (s > 0 && e < INT64_MIN + s) { - /* s is positive: equivalent to e - s < INT64_MIN, but without any - * overflow */ - return INT64_MAX; - } else if (s < 0 && e > INT64_MAX + s) { - /* s is negative: equivalent to e - s > INT64_MAX, but without any - * overflow */ - return INT64_MAX; - } - - return e - s; -} - -/** Return the number of microseconds elapsed between *start and *end. - * Returns LONG_MAX on overflow and underflow. - */ -long -tv_udiff(const struct timeval *start, const struct timeval *end) -{ - /* Sanity check tv_usec */ - if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " - "start tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(start->tv_usec)); - return LONG_MAX; - } - - if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " - "end tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(end->tv_usec)); - return LONG_MAX; - } - - /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit - */ - int64_t udiff; - const int64_t secdiff = tv_secdiff_impl(start, end); - - /* end->tv_usec - start->tv_usec can be up to 1 second either way */ - if (secdiff > (int64_t)(LONG_MAX/1000000 - 1) || - secdiff < (int64_t)(LONG_MIN/1000000 + 1)) { - log_warn(LD_GENERAL, "comparing times on microsecond detail too far " - "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); - return LONG_MAX; - } - - /* we'll never get an overflow here, because we check that both usecs are - * between 0 and TV_USEC_PER_SEC. */ - udiff = secdiff*1000000 + ((int64_t)end->tv_usec - (int64_t)start->tv_usec); - - /* Some compilers are smart enough to work out this is a no-op on L64 */ -#if SIZEOF_LONG < 8 - if (udiff > (int64_t)LONG_MAX || udiff < (int64_t)LONG_MIN) { - return LONG_MAX; - } -#endif - - return (long)udiff; -} - -/** Return the number of milliseconds elapsed between *start and *end. - * If the tv_usec difference is 500, rounds away from zero. - * Returns LONG_MAX on overflow and underflow. - */ -long -tv_mdiff(const struct timeval *start, const struct timeval *end) -{ - /* Sanity check tv_usec */ - if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " - "start tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(start->tv_usec)); - return LONG_MAX; - } - - if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " - "end tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(end->tv_usec)); - return LONG_MAX; - } - - /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit - */ - int64_t mdiff; - const int64_t secdiff = tv_secdiff_impl(start, end); - - /* end->tv_usec - start->tv_usec can be up to 1 second either way, but the - * mdiff calculation may add another temporary second for rounding. - * Whether this actually causes overflow depends on the compiler's constant - * folding and order of operations. */ - if (secdiff > (int64_t)(LONG_MAX/1000 - 2) || - secdiff < (int64_t)(LONG_MIN/1000 + 1)) { - log_warn(LD_GENERAL, "comparing times on millisecond detail too far " - "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); - return LONG_MAX; - } - - /* Subtract and round */ - mdiff = secdiff*1000 + - /* We add a million usec here to ensure that the result is positive, - * so that the round-towards-zero behavior of the division will give - * the right result for rounding to the nearest msec. Later we subtract - * 1000 in order to get the correct result. - * We'll never get an overflow here, because we check that both usecs are - * between 0 and TV_USEC_PER_SEC. */ - ((int64_t)end->tv_usec - (int64_t)start->tv_usec + 500 + 1000000) / 1000 - - 1000; - - /* Some compilers are smart enough to work out this is a no-op on L64 */ -#if SIZEOF_LONG < 8 - if (mdiff > (int64_t)LONG_MAX || mdiff < (int64_t)LONG_MIN) { - return LONG_MAX; - } -#endif - - return (long)mdiff; -} - -/** - * Converts timeval to milliseconds. - */ -int64_t -tv_to_msec(const struct timeval *tv) -{ - int64_t conv = ((int64_t)tv->tv_sec)*1000L; - /* Round ghetto-style */ - conv += ((int64_t)tv->tv_usec+500)/1000L; - return conv; -} - #ifdef _WIN32 HANDLE load_windows_system_library(const TCHAR *library_name) diff --git a/src/common/util.h b/src/common/util.h index 3068f023a4..f174cd3667 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -66,9 +66,6 @@ void tor_log_mallinfo(int severity); /* String manipulation */ /* Time helpers */ -long tv_udiff(const struct timeval *start, const struct timeval *end); -long tv_mdiff(const struct timeval *start, const struct timeval *end); -int64_t tv_to_msec(const struct timeval *tv); /* File helpers */ diff --git a/src/include.am b/src/include.am index 8345813b71..ba5421e093 100644 --- a/src/include.am +++ b/src/include.am @@ -24,6 +24,7 @@ include src/lib/string/include.am include src/lib/smartlist_core/include.am include src/lib/testsupport/include.am include src/lib/thread/include.am +include src/lib/time/include.am include src/lib/tls/include.am include src/lib/trace/include.am include src/lib/wallclock/include.am diff --git a/src/lib/time/.may_include b/src/lib/time/.may_include new file mode 100644 index 0000000000..a35e7a34e1 --- /dev/null +++ b/src/lib/time/.may_include @@ -0,0 +1,8 @@ +orconfig.h + +lib/cc/*.h +lib/err/*.h +lib/intmath/*.h +lib/log/*.h +lib/time/*.h +lib/wallclock/*.h diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c new file mode 100644 index 0000000000..f50ccb5e3d --- /dev/null +++ b/src/lib/time/compat_time.c @@ -0,0 +1,856 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_time.c + * \brief Portable wrappers for finding out the current time, running + * timers, etc. + **/ + +#define COMPAT_TIME_PRIVATE +#include "lib/time/compat_time.h" + +#include "lib/err/torerr.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/intmath/muldiv.h" + +#ifdef _WIN32 +#include +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef TOR_UNIT_TESTS +#if !defined(HAVE_USLEEP) && defined(HAVE_SYS_SELECT_H) +/* as fallback implementation for tor_sleep_msec */ +#include +#endif +#endif /* defined(TOR_UNIT_TESTS) */ + +#ifdef __APPLE__ +#include +#endif + +#include +#include +#include + +#ifdef _WIN32 +#undef HAVE_CLOCK_GETTIME +#endif + +#ifdef TOR_UNIT_TESTS +/** Delay for msec milliseconds. Only used in tests. */ +void +tor_sleep_msec(int msec) +{ +#ifdef _WIN32 + Sleep(msec); +#elif defined(HAVE_USLEEP) + sleep(msec / 1000); + /* Some usleep()s hate sleeping more than 1 sec */ + usleep((msec % 1000) * 1000); +#elif defined(HAVE_SYS_SELECT_H) + struct timeval tv = { msec / 1000, (msec % 1000) * 1000}; + select(0, NULL, NULL, NULL, &tv); +#else + sleep(CEIL_DIV(msec, 1000)); +#endif /* defined(_WIN32) || ... */ +} +#endif /* defined(TOR_UNIT_TESTS) */ + +#define ONE_MILLION ((int64_t) (1000 * 1000)) +#define ONE_BILLION ((int64_t) (1000 * 1000 * 1000)) + +/** True iff monotime_init has been called. */ +static int monotime_initialized = 0; + +static monotime_t initialized_at; +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT +static monotime_coarse_t initialized_at_coarse; +#endif + +#ifdef TOR_UNIT_TESTS +/** True if we are running unit tests and overriding the current monotonic + * time. Note that mocked monotonic time might not be monotonic. + */ +static int monotime_mocking_enabled = 0; +static monotime_t initialized_at_saved; + +static int64_t mock_time_nsec = 0; +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT +static int64_t mock_time_nsec_coarse = 0; +static monotime_coarse_t initialized_at_coarse_saved; +#endif + +void +monotime_enable_test_mocking(void) +{ + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + + tor_assert_nonfatal(monotime_mocking_enabled == 0); + monotime_mocking_enabled = 1; + memcpy(&initialized_at_saved, + &initialized_at, sizeof(monotime_t)); + memset(&initialized_at, 0, sizeof(monotime_t)); +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT + memcpy(&initialized_at_coarse_saved, + &initialized_at_coarse, sizeof(monotime_coarse_t)); + memset(&initialized_at_coarse, 0, sizeof(monotime_coarse_t)); +#endif +} + +void +monotime_disable_test_mocking(void) +{ + tor_assert_nonfatal(monotime_mocking_enabled == 1); + monotime_mocking_enabled = 0; + + memcpy(&initialized_at, + &initialized_at_saved, sizeof(monotime_t)); +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT + memcpy(&initialized_at_coarse, + &initialized_at_coarse_saved, sizeof(monotime_coarse_t)); +#endif +} + +void +monotime_set_mock_time_nsec(int64_t nsec) +{ + tor_assert_nonfatal(monotime_mocking_enabled == 1); + mock_time_nsec = nsec; +} + +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT +void +monotime_coarse_set_mock_time_nsec(int64_t nsec) +{ + tor_assert_nonfatal(monotime_mocking_enabled == 1); + mock_time_nsec_coarse = nsec; +} +#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ +#endif /* defined(TOR_UNIT_TESTS) */ + +/* "ratchet" functions for monotonic time. */ + +#if defined(_WIN32) || defined(TOR_UNIT_TESTS) + +/** Protected by lock: last value returned by monotime_get(). */ +static int64_t last_pctr = 0; +/** Protected by lock: offset we must add to monotonic time values. */ +static int64_t pctr_offset = 0; +/* If we are using GetTickCount(), how many times has it rolled over? */ +static uint32_t rollover_count = 0; +/* If we are using GetTickCount(), what's the last value it returned? */ +static int64_t last_tick_count = 0; + +/** Helper for windows: Called with a sequence of times that are supposed + * to be monotonic; increments them as appropriate so that they actually + * _are_ monotonic. + * + * Caller must hold lock. */ +STATIC int64_t +ratchet_performance_counter(int64_t count_raw) +{ + /* must hold lock */ + const int64_t count_adjusted = count_raw + pctr_offset; + + if (PREDICT_UNLIKELY(count_adjusted < last_pctr)) { + /* Monotonicity failed! Pretend no time elapsed. */ + pctr_offset = last_pctr - count_raw; + return last_pctr; + } else { + last_pctr = count_adjusted; + return count_adjusted; + } +} + +STATIC int64_t +ratchet_coarse_performance_counter(const int64_t count_raw) +{ + int64_t count = count_raw + (((int64_t)rollover_count) << 32); + while (PREDICT_UNLIKELY(count < last_tick_count)) { + ++rollover_count; + count = count_raw + (((int64_t)rollover_count) << 32); + } + last_tick_count = count; + return count; +} +#endif /* defined(_WIN32) || defined(TOR_UNIT_TESTS) */ + +#if defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) +static struct timeval last_timeofday = { 0, 0 }; +static struct timeval timeofday_offset = { 0, 0 }; + +/** Helper for gettimeofday(): Called with a sequence of times that are + * supposed to be monotonic; increments them as appropriate so that they + * actually _are_ monotonic. + * + * Caller must hold lock. */ +STATIC void +ratchet_timeval(const struct timeval *timeval_raw, struct timeval *out) +{ + /* must hold lock */ + timeradd(timeval_raw, &timeofday_offset, out); + if (PREDICT_UNLIKELY(timercmp(out, &last_timeofday, OP_LT))) { + /* time ran backwards. Instead, declare that no time occurred. */ + timersub(&last_timeofday, timeval_raw, &timeofday_offset); + memcpy(out, &last_timeofday, sizeof(struct timeval)); + } else { + memcpy(&last_timeofday, out, sizeof(struct timeval)); + } +} +#endif /* defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) */ + +#ifdef TOR_UNIT_TESTS +/** For testing: reset all the ratchets */ +void +monotime_reset_ratchets_for_testing(void) +{ + last_pctr = pctr_offset = last_tick_count = 0; + rollover_count = 0; + memset(&last_timeofday, 0, sizeof(struct timeval)); + memset(&timeofday_offset, 0, sizeof(struct timeval)); +} +#endif /* defined(TOR_UNIT_TESTS) */ + +#ifdef __APPLE__ + +/** Initialized on startup: tells is how to convert from ticks to + * nanoseconds. + */ +static struct mach_timebase_info mach_time_info; +static struct mach_timebase_info mach_time_info_msec_cvt; +static int monotime_shift = 0; + +static void +monotime_init_internal(void) +{ + tor_assert(!monotime_initialized); + int r = mach_timebase_info(&mach_time_info); + tor_assert(r == 0); + tor_assert(mach_time_info.denom != 0); + + { + // approximate only. + uint64_t ns_per_tick = mach_time_info.numer / mach_time_info.denom; + uint64_t ms_per_tick = ns_per_tick * ONE_MILLION; + // requires that tor_log2(0) == 0. + monotime_shift = tor_log2(ms_per_tick); + } + { + // For converting ticks to milliseconds in a 32-bit-friendly way, we + // will first right-shift by 20, and then multiply by 20/19, since + // (1<<20) * 19/20 is about 1e6. We precompute a new numerate and + // denominator here to avoid multiple multiplies. + mach_time_info_msec_cvt.numer = mach_time_info.numer * 20; + mach_time_info_msec_cvt.denom = mach_time_info.denom * 19; + } +} + +/** + * Set "out" to the most recent monotonic time value + */ +void +monotime_get(monotime_t *out) +{ +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->abstime_ = (mock_time_nsec * mach_time_info.denom) + / mach_time_info.numer; + return; + } +#endif /* defined(TOR_UNIT_TESTS) */ + out->abstime_ = mach_absolute_time(); +} + +#if defined(HAVE_MACH_APPROXIMATE_TIME) +void +monotime_coarse_get(monotime_coarse_t *out) +{ +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->abstime_ = (mock_time_nsec_coarse * mach_time_info.denom) + / mach_time_info.numer; + return; + } +#endif /* defined(TOR_UNIT_TESTS) */ + out->abstime_ = mach_approximate_time(); +} +#endif + +/** + * Return the number of nanoseconds between start and end. + */ +int64_t +monotime_diff_nsec(const monotime_t *start, + const monotime_t *end) +{ + if (BUG(mach_time_info.denom == 0)) { + monotime_init(); + } + const int64_t diff_ticks = end->abstime_ - start->abstime_; + const int64_t diff_nsec = + (diff_ticks * mach_time_info.numer) / mach_time_info.denom; + return diff_nsec; +} + +int32_t +monotime_coarse_diff_msec32_(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ + if (BUG(mach_time_info.denom == 0)) { + monotime_init(); + } + const int64_t diff_ticks = end->abstime_ - start->abstime_; + + /* We already require in di_ops.c that right-shift performs a sign-extend. */ + const int32_t diff_microticks = (int32_t)(diff_ticks >> 20); + + return (diff_microticks * mach_time_info_msec_cvt.numer) / + mach_time_info_msec_cvt.denom; +} + +uint32_t +monotime_coarse_to_stamp(const monotime_coarse_t *t) +{ + return (uint32_t)(t->abstime_ >> monotime_shift); +} + +int +monotime_is_zero(const monotime_t *val) +{ + return val->abstime_ == 0; +} + +void +monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) +{ + const uint64_t nsec = msec * ONE_MILLION; + const uint64_t ticks = (nsec * mach_time_info.denom) / mach_time_info.numer; + out->abstime_ = val->abstime_ + ticks; +} + +/* end of "__APPLE__" */ +#elif defined(HAVE_CLOCK_GETTIME) + +#ifdef CLOCK_MONOTONIC_COARSE +/** + * Which clock should we use for coarse-grained monotonic time? By default + * this is CLOCK_MONOTONIC_COARSE, but it might not work -- for example, + * if we're compiled with newer Linux headers and then we try to run on + * an old Linux kernel. In that case, we will fall back to CLOCK_MONOTONIC. + */ +static int clock_monotonic_coarse = CLOCK_MONOTONIC_COARSE; +#endif /* defined(CLOCK_MONOTONIC_COARSE) */ + +static void +monotime_init_internal(void) +{ +#ifdef CLOCK_MONOTONIC_COARSE + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) < 0) { + log_info(LD_GENERAL, "CLOCK_MONOTONIC_COARSE isn't working (%s); " + "falling back to CLOCK_MONOTONIC.", strerror(errno)); + clock_monotonic_coarse = CLOCK_MONOTONIC; + } +#endif /* defined(CLOCK_MONOTONIC_COARSE) */ +} + +void +monotime_get(monotime_t *out) +{ +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->ts_.tv_sec = (time_t) (mock_time_nsec / ONE_BILLION); + out->ts_.tv_nsec = (int) (mock_time_nsec % ONE_BILLION); + return; + } +#endif /* defined(TOR_UNIT_TESTS) */ + int r = clock_gettime(CLOCK_MONOTONIC, &out->ts_); + tor_assert(r == 0); +} + +#ifdef CLOCK_MONOTONIC_COARSE +void +monotime_coarse_get(monotime_coarse_t *out) +{ +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->ts_.tv_sec = (time_t) (mock_time_nsec_coarse / ONE_BILLION); + out->ts_.tv_nsec = (int) (mock_time_nsec_coarse % ONE_BILLION); + return; + } +#endif /* defined(TOR_UNIT_TESTS) */ + int r = clock_gettime(clock_monotonic_coarse, &out->ts_); + if (PREDICT_UNLIKELY(r < 0) && + errno == EINVAL && + clock_monotonic_coarse == CLOCK_MONOTONIC_COARSE) { + /* We should have caught this at startup in monotime_init_internal! + */ + log_warn(LD_BUG, "Falling back to non-coarse monotonic time %s initial " + "system start?", monotime_initialized?"after":"without"); + clock_monotonic_coarse = CLOCK_MONOTONIC; + r = clock_gettime(clock_monotonic_coarse, &out->ts_); + } + + tor_assert(r == 0); +} +#endif /* defined(CLOCK_MONOTONIC_COARSE) */ + +int64_t +monotime_diff_nsec(const monotime_t *start, + const monotime_t *end) +{ + const int64_t diff_sec = end->ts_.tv_sec - start->ts_.tv_sec; + const int64_t diff_nsec = diff_sec * ONE_BILLION + + (end->ts_.tv_nsec - start->ts_.tv_nsec); + + return diff_nsec; +} + +int32_t +monotime_coarse_diff_msec32_(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ + const int32_t diff_sec = (int32_t)(end->ts_.tv_sec - start->ts_.tv_sec); + const int32_t diff_nsec = (int32_t)(end->ts_.tv_nsec - start->ts_.tv_nsec); + return diff_sec * 1000 + diff_nsec / ONE_MILLION; +} + +/* This value is ONE_BILLION >> 20. */ +static const uint32_t STAMP_TICKS_PER_SECOND = 953; + +uint32_t +monotime_coarse_to_stamp(const monotime_coarse_t *t) +{ + uint32_t nsec = (uint32_t)t->ts_.tv_nsec; + uint32_t sec = (uint32_t)t->ts_.tv_sec; + + return (sec * STAMP_TICKS_PER_SECOND) + (nsec >> 20); +} + +int +monotime_is_zero(const monotime_t *val) +{ + return val->ts_.tv_sec == 0 && val->ts_.tv_nsec == 0; +} + +void +monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) +{ + const uint32_t sec = msec / 1000; + const uint32_t msec_remainder = msec % 1000; + out->ts_.tv_sec = val->ts_.tv_sec + sec; + out->ts_.tv_nsec = val->ts_.tv_nsec + (msec_remainder * ONE_MILLION); + if (out->ts_.tv_nsec > ONE_BILLION) { + out->ts_.tv_nsec -= ONE_BILLION; + out->ts_.tv_sec += 1; + } +} + +/* end of "HAVE_CLOCK_GETTIME" */ +#elif defined (_WIN32) + +/** Result of QueryPerformanceFrequency, in terms needed to + * convert ticks to nanoseconds. */ +static int64_t nsec_per_tick_numer = 1; +static int64_t nsec_per_tick_denom = 1; + +/** Lock to protect last_pctr and pctr_offset */ +static CRITICAL_SECTION monotime_lock; +/** Lock to protect rollover_count and last_tick_count */ +static CRITICAL_SECTION monotime_coarse_lock; + +typedef ULONGLONG (WINAPI *GetTickCount64_fn_t)(void); +static GetTickCount64_fn_t GetTickCount64_fn = NULL; + +static void +monotime_init_internal(void) +{ + tor_assert(!monotime_initialized); + BOOL ok = InitializeCriticalSectionAndSpinCount(&monotime_lock, 200); + tor_assert(ok); + ok = InitializeCriticalSectionAndSpinCount(&monotime_coarse_lock, 200); + tor_assert(ok); + LARGE_INTEGER li; + ok = QueryPerformanceFrequency(&li); + tor_assert(ok); + tor_assert(li.QuadPart); + + uint64_t n = ONE_BILLION; + uint64_t d = li.QuadPart; + /* We need to simplify this or we'll probably overflow the int64. */ + simplify_fraction64(&n, &d); + tor_assert(n <= INT64_MAX); + tor_assert(d <= INT64_MAX); + + nsec_per_tick_numer = (int64_t) n; + nsec_per_tick_denom = (int64_t) d; + + last_pctr = 0; + pctr_offset = 0; + + HANDLE h = load_windows_system_library(TEXT("kernel32.dll")); + if (h) { + GetTickCount64_fn = (GetTickCount64_fn_t) + GetProcAddress(h, "GetTickCount64"); + } + // FreeLibrary(h) ? +} + +void +monotime_get(monotime_t *out) +{ + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->pcount_ = (mock_time_nsec * nsec_per_tick_denom) + / nsec_per_tick_numer; + return; + } +#endif /* defined(TOR_UNIT_TESTS) */ + + /* Alas, QueryPerformanceCounter is not always monotonic: see bug list at + + https://www.python.org/dev/peps/pep-0418/#windows-queryperformancecounter + */ + + EnterCriticalSection(&monotime_lock); + LARGE_INTEGER res; + BOOL ok = QueryPerformanceCounter(&res); + tor_assert(ok); + const int64_t count_raw = res.QuadPart; + out->pcount_ = ratchet_performance_counter(count_raw); + LeaveCriticalSection(&monotime_lock); +} + +void +monotime_coarse_get(monotime_coarse_t *out) +{ +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->tick_count_ = mock_time_nsec_coarse / ONE_MILLION; + return; + } +#endif /* defined(TOR_UNIT_TESTS) */ + + if (GetTickCount64_fn) { + out->tick_count_ = (int64_t)GetTickCount64_fn(); + } else { + EnterCriticalSection(&monotime_coarse_lock); + DWORD tick = GetTickCount(); + out->tick_count_ = ratchet_coarse_performance_counter(tick); + LeaveCriticalSection(&monotime_coarse_lock); + } +} + +int64_t +monotime_diff_nsec(const monotime_t *start, + const monotime_t *end) +{ + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + const int64_t diff_ticks = end->pcount_ - start->pcount_; + return (diff_ticks * nsec_per_tick_numer) / nsec_per_tick_denom; +} + +int64_t +monotime_coarse_diff_msec(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ + const int64_t diff_ticks = end->tick_count_ - start->tick_count_; + return diff_ticks; +} + +int32_t +monotime_coarse_diff_msec32_(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ + return (int32_t)monotime_coarse_diff_msec(start, end); +} + +int64_t +monotime_coarse_diff_usec(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ + return monotime_coarse_diff_msec(start, end) * 1000; +} + +int64_t +monotime_coarse_diff_nsec(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ + return monotime_coarse_diff_msec(start, end) * ONE_MILLION; +} + +static const uint32_t STAMP_TICKS_PER_SECOND = 1000; + +uint32_t +monotime_coarse_to_stamp(const monotime_coarse_t *t) +{ + return (uint32_t) t->tick_count_; +} + +int +monotime_is_zero(const monotime_t *val) +{ + return val->pcount_ == 0; +} + +int +monotime_coarse_is_zero(const monotime_coarse_t *val) +{ + return val->tick_count_ == 0; +} + +void +monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) +{ + const uint64_t nsec = msec * ONE_MILLION; + const uint64_t ticks = (nsec * nsec_per_tick_denom) / nsec_per_tick_numer; + out->pcount_ = val->pcount_ + ticks; +} + +void +monotime_coarse_add_msec(monotime_coarse_t *out, const monotime_coarse_t *val, + uint32_t msec) +{ + out->tick_count_ = val->tick_count_ + msec; +} + +/* end of "_WIN32" */ +#elif defined(MONOTIME_USING_GETTIMEOFDAY) + +static tor_mutex_t monotime_lock; + +/** Initialize the monotonic timer subsystem. */ +static void +monotime_init_internal(void) +{ + tor_assert(!monotime_initialized); + tor_mutex_init(&monotime_lock); +} + +void +monotime_get(monotime_t *out) +{ + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + + tor_mutex_acquire(&monotime_lock); + struct timeval timeval_raw; + tor_gettimeofday(&timeval_raw); + ratchet_timeval(&timeval_raw, &out->tv_); + tor_mutex_release(&monotime_lock); +} + +int64_t +monotime_diff_nsec(const monotime_t *start, + const monotime_t *end) +{ + struct timeval diff; + timersub(&end->tv_, &start->tv_, &diff); + return (diff.tv_sec * ONE_BILLION + diff.tv_usec * 1000); +} + +int32_t +monotime_coarse_diff_msec32_(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ + struct timeval diff; + timersub(&end->tv_, &start->tv_, &diff); + return diff.tv_sec * 1000 + diff.tv_usec / 1000; +} + +/* This value is ONE_MILLION >> 10. */ +static const uint32_t STAMP_TICKS_PER_SECOND = 976; + +uint32_t +monotime_coarse_to_stamp(const monotime_coarse_t *t) +{ + const uint32_t usec = (uint32_t)t->tv_.tv_usec; + const uint32_t sec = (uint32_t)t->tv_.tv_sec; + return (sec * STAMP_TICKS_PER_SECOND) | (nsec >> 10); +} + +int +monotime_is_zero(const monotime_t *val) +{ + return val->tv_.tv_sec == 0 && val->tv_.tv_usec == 0; +} + +void +monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec) +{ + const uint32_t sec = msec / 1000; + const uint32_t msec_remainder = msec % 1000; + out->tv_.tv_sec = val->tv_.tv_sec + sec; + out->tv_.tv_usec = val->tv_.tv_nsec + (msec_remainder * 1000); + if (out->tv_.tv_usec > ONE_MILLION) { + out->tv_.tv_usec -= ONE_MILLION; + out->tv_.tv_sec += 1; + } +} + +/* end of "MONOTIME_USING_GETTIMEOFDAY" */ +#else +#error "No way to implement monotonic timers." +#endif /* defined(__APPLE__) || ... */ + +/** + * Initialize the monotonic timer subsystem. Must be called before any + * monotonic timer functions. This function is idempotent. + */ +void +monotime_init(void) +{ + if (!monotime_initialized) { + monotime_init_internal(); + monotime_initialized = 1; + monotime_get(&initialized_at); +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT + monotime_coarse_get(&initialized_at_coarse); +#endif + } +} + +void +monotime_zero(monotime_t *out) +{ + memset(out, 0, sizeof(*out)); +} +#ifdef MONOTIME_COARSE_TYPE_IS_DIFFERENT +void +monotime_coarse_zero(monotime_coarse_t *out) +{ + memset(out, 0, sizeof(*out)); +} +#endif + +int64_t +monotime_diff_usec(const monotime_t *start, + const monotime_t *end) +{ + const int64_t nsec = monotime_diff_nsec(start, end); + return CEIL_DIV(nsec, 1000); +} + +int64_t +monotime_diff_msec(const monotime_t *start, + const monotime_t *end) +{ + const int64_t nsec = monotime_diff_nsec(start, end); + return CEIL_DIV(nsec, ONE_MILLION); +} + +uint64_t +monotime_absolute_nsec(void) +{ + monotime_t now; + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + + monotime_get(&now); + return monotime_diff_nsec(&initialized_at, &now); +} + +uint64_t +monotime_absolute_usec(void) +{ + return monotime_absolute_nsec() / 1000; +} + +uint64_t +monotime_absolute_msec(void) +{ + return monotime_absolute_nsec() / ONE_MILLION; +} + +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT +uint64_t +monotime_coarse_absolute_nsec(void) +{ + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + + monotime_coarse_t now; + monotime_coarse_get(&now); + return monotime_coarse_diff_nsec(&initialized_at_coarse, &now); +} + +uint64_t +monotime_coarse_absolute_usec(void) +{ + return monotime_coarse_absolute_nsec() / 1000; +} + +uint64_t +monotime_coarse_absolute_msec(void) +{ + return monotime_coarse_absolute_nsec() / ONE_MILLION; +} +#else +#define initialized_at_coarse initialized_at +#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ + +/** + * Return the current time "stamp" as described by monotime_coarse_to_stamp. + */ +uint32_t +monotime_coarse_get_stamp(void) +{ + monotime_coarse_t now; + monotime_coarse_get(&now); + return monotime_coarse_to_stamp(&now); +} + +#ifdef __APPLE__ +uint64_t +monotime_coarse_stamp_units_to_approx_msec(uint64_t units) +{ + /* Recover as much precision as we can. */ + uint64_t abstime_diff = (units << monotime_shift); + return (abstime_diff * mach_time_info.numer) / + (mach_time_info.denom * ONE_MILLION); +} +uint64_t +monotime_msec_to_approx_coarse_stamp_units(uint64_t msec) +{ + uint64_t abstime_val = + (((uint64_t)msec) * ONE_MILLION * mach_time_info.denom) / + mach_time_info.numer; + return abstime_val >> monotime_shift; +} +#else +uint64_t +monotime_coarse_stamp_units_to_approx_msec(uint64_t units) +{ + return (units * 1000) / STAMP_TICKS_PER_SECOND; +} +uint64_t +monotime_msec_to_approx_coarse_stamp_units(uint64_t msec) +{ + return (msec * STAMP_TICKS_PER_SECOND) / 1000; +} +#endif diff --git a/src/lib/time/compat_time.h b/src/lib/time/compat_time.h new file mode 100644 index 0000000000..4427ce8f92 --- /dev/null +++ b/src/lib/time/compat_time.h @@ -0,0 +1,234 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_time.h + * + * \brief Functions and types for monotonic times. + * + * monotime_* functions try to provide a high-resolution monotonic timer with + * something the best resolution the system provides. monotime_coarse_* + * functions run faster (if the operating system gives us a way to do that) + * but produce a less accurate timer: accuracy will probably be on the order + * of tens of milliseconds. + */ + +#ifndef TOR_COMPAT_TIME_H +#define TOR_COMPAT_TIME_H + +#include "orconfig.h" +#include "lib/cc/torint.h" + +#include "lib/wallclock/tor_gettimeofday.h" + +#ifdef _WIN32 +#undef HAVE_CLOCK_GETTIME +#endif + +#if defined(HAVE_CLOCK_GETTIME) +/* to ensure definition of CLOCK_MONOTONIC_COARSE if it's there */ +#include +#endif + +#if !defined(HAVE_STRUCT_TIMEVAL_TV_SEC) +/** Implementation of timeval for platforms that don't have it. */ +struct timeval { + time_t tv_sec; + unsigned int tv_usec; +}; +#endif /* !defined(HAVE_STRUCT_TIMEVAL_TV_SEC) */ + +/** Represents a monotonic timer in a platform-dependent way. */ +typedef struct monotime_t { +#ifdef __APPLE__ + /* On apple, there is a 64-bit counter whose precision we must look up. */ + uint64_t abstime_; +#elif defined(HAVE_CLOCK_GETTIME) + /* It sure would be nice to use clock_gettime(). Posix is a nice thing. */ + struct timespec ts_; +#elif defined (_WIN32) + /* On Windows, there is a 64-bit counter whose precision we must look up. */ + int64_t pcount_; +#else +#define MONOTIME_USING_GETTIMEOFDAY + /* Otherwise, we will be stuck using gettimeofday. */ + struct timeval tv_; +#endif /* defined(__APPLE__) || ... */ +} monotime_t; + +#if defined(CLOCK_MONOTONIC_COARSE) && \ + defined(HAVE_CLOCK_GETTIME) +#define MONOTIME_COARSE_FN_IS_DIFFERENT +#define monotime_coarse_t monotime_t +#elif defined(_WIN32) +#define MONOTIME_COARSE_FN_IS_DIFFERENT +#define MONOTIME_COARSE_TYPE_IS_DIFFERENT +/** Represents a coarse monotonic time in a platform-independent way. */ +typedef struct monotime_coarse_t { + uint64_t tick_count_; +} monotime_coarse_t; +#elif defined(__APPLE__) && defined(HAVE_MACH_APPROXIMATE_TIME) +#define MONOTIME_COARSE_FN_IS_DIFFERENT +#define monotime_coarse_t monotime_t +#else +#define monotime_coarse_t monotime_t +#endif /* defined(CLOCK_MONOTONIC_COARSE) && ... || ... */ + +/** + * Initialize the timing subsystem. This function is idempotent. + */ +void monotime_init(void); +/** + * Set out to the current time. + */ +void monotime_get(monotime_t *out); +/** + * Return the number of nanoseconds between start and end. + */ +int64_t monotime_diff_nsec(const monotime_t *start, const monotime_t *end); +/** + * Return the number of microseconds between start and end. + */ +int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end); +/** + * Return the number of milliseconds between start and end. + */ +int64_t monotime_diff_msec(const monotime_t *start, const monotime_t *end); +/** + * Return the number of nanoseconds since the timer system was initialized. + */ +uint64_t monotime_absolute_nsec(void); +/** + * Return the number of microseconds since the timer system was initialized. + */ +uint64_t monotime_absolute_usec(void); +/** + * Return the number of milliseconds since the timer system was initialized. + */ +uint64_t monotime_absolute_msec(void); + +/** + * Set out to zero. + */ +void monotime_zero(monotime_t *out); +/** + * Return true iff out is zero + */ +int monotime_is_zero(const monotime_t *out); + +/** + * Set out to N milliseconds after val. + */ +/* XXXX We should add a more generic function here if we ever need to */ +void monotime_add_msec(monotime_t *out, const monotime_t *val, uint32_t msec); + +#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT) +/** + * Set out to the current coarse time. + */ +void monotime_coarse_get(monotime_coarse_t *out); +uint64_t monotime_coarse_absolute_nsec(void); +uint64_t monotime_coarse_absolute_usec(void); +uint64_t monotime_coarse_absolute_msec(void); +#else /* !(defined(MONOTIME_COARSE_FN_IS_DIFFERENT)) */ +#define monotime_coarse_get monotime_get +#define monotime_coarse_absolute_nsec monotime_absolute_nsec +#define monotime_coarse_absolute_usec monotime_absolute_usec +#define monotime_coarse_absolute_msec monotime_absolute_msec +#endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ + +/** + * Return a "timestamp" approximation for a coarse monotonic timer. + * This timestamp is meant to be fast to calculate and easy to + * compare, and have a unit of something roughly around 1 msec. + * + * It will wrap over from time to time. + * + * It has no defined zero point. + */ +uint32_t monotime_coarse_to_stamp(const monotime_coarse_t *t); +/** + * Convert a difference, expressed in the units of monotime_coarse_to_stamp, + * into an approximate number of milliseconds. + */ +uint64_t monotime_coarse_stamp_units_to_approx_msec(uint64_t units); +uint64_t monotime_msec_to_approx_coarse_stamp_units(uint64_t msec); +uint32_t monotime_coarse_get_stamp(void); + +#if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) +int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start, + const monotime_coarse_t *end); +int64_t monotime_coarse_diff_usec(const monotime_coarse_t *start, + const monotime_coarse_t *end); +int64_t monotime_coarse_diff_msec(const monotime_coarse_t *start, + const monotime_coarse_t *end); +void monotime_coarse_zero(monotime_coarse_t *out); +int monotime_coarse_is_zero(const monotime_coarse_t *val); +void monotime_coarse_add_msec(monotime_coarse_t *out, + const monotime_coarse_t *val, uint32_t msec); +#else /* !(defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT)) */ +#define monotime_coarse_diff_nsec monotime_diff_nsec +#define monotime_coarse_diff_usec monotime_diff_usec +#define monotime_coarse_diff_msec monotime_diff_msec +#define monotime_coarse_zero monotime_zero +#define monotime_coarse_is_zero monotime_is_zero +#define monotime_coarse_add_msec monotime_add_msec +#endif /* defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) */ + +/** + * As monotime_coarse_diff_msec, but avoid 64-bit division. + * + * Requires that the difference fit into an int32_t; not for use with + * large time differences. + */ +int32_t monotime_coarse_diff_msec32_(const monotime_coarse_t *start, + const monotime_coarse_t *end); + +/** + * As monotime_coarse_diff_msec, but avoid 64-bit division if it is expensive. + * + * Requires that the difference fit into an int32_t; not for use with + * large time differences. + */ +static inline int32_t +monotime_coarse_diff_msec32(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ +#if SIZEOF_VOID_P == 8 + // on a 64-bit platform, let's assume 64/64 division is cheap. + return (int32_t) monotime_coarse_diff_msec(start, end); +#else + return monotime_coarse_diff_msec32_(start, end); +#endif +} + +#ifdef TOR_UNIT_TESTS +void tor_sleep_msec(int msec); + +void monotime_enable_test_mocking(void); +void monotime_disable_test_mocking(void); +void monotime_set_mock_time_nsec(int64_t); +#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT) +void monotime_coarse_set_mock_time_nsec(int64_t); +#else +#define monotime_coarse_set_mock_time_nsec monotime_set_mock_time_nsec +#endif +#endif /* defined(TOR_UNIT_TESTS) */ + +#ifdef COMPAT_TIME_PRIVATE +#if defined(_WIN32) || defined(TOR_UNIT_TESTS) +STATIC int64_t ratchet_performance_counter(int64_t count_raw); +STATIC int64_t ratchet_coarse_performance_counter(int64_t count_raw); +#endif +#if defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) +STATIC void ratchet_timeval(const struct timeval *timeval_raw, + struct timeval *out); +#endif +#ifdef TOR_UNIT_TESTS +void monotime_reset_ratchets_for_testing(void); +#endif +#endif /* defined(COMPAT_TIME_PRIVATE) */ + +#endif /* !defined(TOR_COMPAT_TIME_H) */ diff --git a/src/lib/time/include.am b/src/lib/time/include.am new file mode 100644 index 0000000000..a3f93a3744 --- /dev/null +++ b/src/lib/time/include.am @@ -0,0 +1,19 @@ + +noinst_LIBRARIES += src/lib/libtor-time.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-time-testing.a +endif + +src_lib_libtor_time_a_SOURCES = \ + src/lib/time/compat_time.c \ + src/lib/time/tvdiff.c + +src_lib_libtor_time_testing_a_SOURCES = \ + $(src_lib_libtor_time_a_SOURCES) +src_lib_libtor_time_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_time_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/time/compat_time.h \ + src/lib/time/tvdiff.h diff --git a/src/lib/time/tvdiff.c b/src/lib/time/tvdiff.c new file mode 100644 index 0000000000..11c881234a --- /dev/null +++ b/src/lib/time/tvdiff.c @@ -0,0 +1,155 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/time/tvdiff.h" + +#include "lib/cc/compat_compiler.h" +#include "lib/log/torlog.h" + +#define TOR_USEC_PER_SEC 1000000 + +/** Return the difference between start->tv_sec and end->tv_sec. + * Returns INT64_MAX on overflow and underflow. + */ +static int64_t +tv_secdiff_impl(const struct timeval *start, const struct timeval *end) +{ + const int64_t s = (int64_t)start->tv_sec; + const int64_t e = (int64_t)end->tv_sec; + + /* This may not be the most efficient way of implemeting this check, + * but it's easy to see that it's correct and doesn't overflow */ + + if (s > 0 && e < INT64_MIN + s) { + /* s is positive: equivalent to e - s < INT64_MIN, but without any + * overflow */ + return INT64_MAX; + } else if (s < 0 && e > INT64_MAX + s) { + /* s is negative: equivalent to e - s > INT64_MAX, but without any + * overflow */ + return INT64_MAX; + } + + return e - s; +} + +/** Return the number of microseconds elapsed between *start and *end. + * Returns LONG_MAX on overflow and underflow. + */ +long +tv_udiff(const struct timeval *start, const struct timeval *end) +{ + /* Sanity check tv_usec */ + if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " + "start tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(start->tv_usec)); + return LONG_MAX; + } + + if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " + "end tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(end->tv_usec)); + return LONG_MAX; + } + + /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit + */ + int64_t udiff; + const int64_t secdiff = tv_secdiff_impl(start, end); + + /* end->tv_usec - start->tv_usec can be up to 1 second either way */ + if (secdiff > (int64_t)(LONG_MAX/1000000 - 1) || + secdiff < (int64_t)(LONG_MIN/1000000 + 1)) { + log_warn(LD_GENERAL, "comparing times on microsecond detail too far " + "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); + return LONG_MAX; + } + + /* we'll never get an overflow here, because we check that both usecs are + * between 0 and TV_USEC_PER_SEC. */ + udiff = secdiff*1000000 + ((int64_t)end->tv_usec - (int64_t)start->tv_usec); + + /* Some compilers are smart enough to work out this is a no-op on L64 */ +#if SIZEOF_LONG < 8 + if (udiff > (int64_t)LONG_MAX || udiff < (int64_t)LONG_MIN) { + return LONG_MAX; + } +#endif + + return (long)udiff; +} + +/** Return the number of milliseconds elapsed between *start and *end. + * If the tv_usec difference is 500, rounds away from zero. + * Returns LONG_MAX on overflow and underflow. + */ +long +tv_mdiff(const struct timeval *start, const struct timeval *end) +{ + /* Sanity check tv_usec */ + if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " + "start tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(start->tv_usec)); + return LONG_MAX; + } + + if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " + "end tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(end->tv_usec)); + return LONG_MAX; + } + + /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit + */ + int64_t mdiff; + const int64_t secdiff = tv_secdiff_impl(start, end); + + /* end->tv_usec - start->tv_usec can be up to 1 second either way, but the + * mdiff calculation may add another temporary second for rounding. + * Whether this actually causes overflow depends on the compiler's constant + * folding and order of operations. */ + if (secdiff > (int64_t)(LONG_MAX/1000 - 2) || + secdiff < (int64_t)(LONG_MIN/1000 + 1)) { + log_warn(LD_GENERAL, "comparing times on millisecond detail too far " + "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); + return LONG_MAX; + } + + /* Subtract and round */ + mdiff = secdiff*1000 + + /* We add a million usec here to ensure that the result is positive, + * so that the round-towards-zero behavior of the division will give + * the right result for rounding to the nearest msec. Later we subtract + * 1000 in order to get the correct result. + * We'll never get an overflow here, because we check that both usecs are + * between 0 and TV_USEC_PER_SEC. */ + ((int64_t)end->tv_usec - (int64_t)start->tv_usec + 500 + 1000000) / 1000 + - 1000; + + /* Some compilers are smart enough to work out this is a no-op on L64 */ +#if SIZEOF_LONG < 8 + if (mdiff > (int64_t)LONG_MAX || mdiff < (int64_t)LONG_MIN) { + return LONG_MAX; + } +#endif + + return (long)mdiff; +} + +/** + * Converts timeval to milliseconds. + */ +int64_t +tv_to_msec(const struct timeval *tv) +{ + int64_t conv = ((int64_t)tv->tv_sec)*1000L; + /* Round ghetto-style */ + conv += ((int64_t)tv->tv_usec+500)/1000L; + return conv; +} diff --git a/src/lib/time/tvdiff.h b/src/lib/time/tvdiff.h new file mode 100644 index 0000000000..215de9cf37 --- /dev/null +++ b/src/lib/time/tvdiff.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_TVDIFF_H +#define TOR_TVDIFF_H + +#include "lib/cc/torint.h" +struct timeval; + +long tv_udiff(const struct timeval *start, const struct timeval *end); +long tv_mdiff(const struct timeval *start, const struct timeval *end); +int64_t tv_to_msec(const struct timeval *tv); + +#endif diff --git a/src/lib/wallclock/include.am b/src/lib/wallclock/include.am index 7b735e97ee..7864c21e16 100644 --- a/src/lib/wallclock/include.am +++ b/src/lib/wallclock/include.am @@ -17,5 +17,6 @@ src_lib_libtor_wallclock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) noinst_HEADERS += \ src/lib/wallclock/approx_time.h \ + src/lib/wallclock/timeval.h \ src/lib/wallclock/tm_cvt.h \ src/lib/wallclock/tor_gettimeofday.h diff --git a/src/lib/wallclock/timeval.c b/src/lib/wallclock/timeval.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/lib/wallclock/timeval.h b/src/lib/wallclock/timeval.h new file mode 100644 index 0000000000..6a9b36a022 --- /dev/null +++ b/src/lib/wallclock/timeval.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_TIMEVAL_H +#define TOR_TIMEVAL_H + +#include "orconfig.h" +#include "lib/cc/torint.h" + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifndef timeradd +/** Replacement for timeradd on platforms that do not have it: sets tvout to + * the sum of tv1 and tv2. */ +#define timeradd(tv1,tv2,tvout) \ + do { \ + (tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \ + (tvout)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \ + if ((tvout)->tv_usec >= 1000000) { \ + (tvout)->tv_usec -= 1000000; \ + (tvout)->tv_sec++; \ + } \ + } while (0) +#endif /* !defined(timeradd) */ + +#ifndef timersub +/** Replacement for timersub on platforms that do not have it: sets tvout to + * tv1 minus tv2. */ +#define timersub(tv1,tv2,tvout) \ + do { \ + (tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec; \ + (tvout)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec; \ + if ((tvout)->tv_usec < 0) { \ + (tvout)->tv_usec += 1000000; \ + (tvout)->tv_sec--; \ + } \ + } while (0) +#endif /* !defined(timersub) */ + +#ifndef timercmp +/** Replacement for timercmp on platforms that do not have it: returns true + * iff the relational operator "op" makes the expression tv1 op tv2 true. + * + * Note that while this definition should work for all boolean operators, some + * platforms' native timercmp definitions do not support >=, <=, or ==. So + * don't use those. + */ +#define timercmp(tv1,tv2,op) \ + (((tv1)->tv_sec == (tv2)->tv_sec) ? \ + ((tv1)->tv_usec op (tv2)->tv_usec) : \ + ((tv1)->tv_sec op (tv2)->tv_sec)) +#endif /* !defined(timercmp) */ + +#endif diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c index 08186ca9a9..c2abb2d14b 100644 --- a/src/or/circuitstats.c +++ b/src/or/circuitstats.c @@ -41,6 +41,7 @@ #include "or/circuitlist.h" #include "or/circuituse.h" #include "lib/math/fp.h" +#include "lib/time/tvdiff.h" #include "or/crypt_path_st.h" #include "or/origin_circuit_st.h" diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 3669eb7f16..71abd5d6ce 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -57,6 +57,7 @@ #include "or/router.h" #include "or/routerlist.h" #include "lib/math/fp.h" +#include "lib/time/tvdiff.h" #include "or/cpath_build_state_st.h" #include "or/dir_connection_st.h" diff --git a/src/or/geoip.c b/src/or/geoip.c index 330477e4ce..4a55e3f8db 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -39,6 +39,7 @@ #include "or/routerlist.h" #include "lib/container/order.h" +#include "lib/time/tvdiff.h" static void init_geoip_countries(void); diff --git a/src/test/test_util.c b/src/test/test_util.c index 8fe308826b..220b05b49b 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -31,6 +31,7 @@ #include "lib/thread/numcpus.h" #include "lib/math/fp.h" #include "lib/math/laplace.h" +#include "lib/time/tvdiff.h" #ifdef HAVE_PWD_H #include -- cgit v1.2.3-54-g00ecf