mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
Merge branch 'monotonic_v2_squashed'
This commit is contained in:
commit
558f7d3701
6
changes/monotonic
Normal file
6
changes/monotonic
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
o Minor features (backend):
|
||||||
|
- Tor now uses the operating system's monotonic timers (where available)
|
||||||
|
for internal fine-grained timing. Previously we would look at the
|
||||||
|
system clock, and then attempt to compensate for the clock running
|
||||||
|
backwards. Closes ticket 18908.
|
||||||
|
|
@ -33,6 +33,12 @@
|
|||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_UTIME_H
|
||||||
|
#include <utime.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SYS_UTIME_H
|
||||||
|
#include <sys/utime.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
@ -89,12 +95,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
|
|||||||
#include "tor_readpassphrase.h"
|
#include "tor_readpassphrase.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_GETTIMEOFDAY
|
|
||||||
#ifdef HAVE_FTIME
|
|
||||||
#include <sys/timeb.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Includes for the process attaching prevention */
|
/* Includes for the process attaching prevention */
|
||||||
#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
|
#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
|
||||||
/* Only use the linux prctl; the IRIX prctl is totally different */
|
/* Only use the linux prctl; the IRIX prctl is totally different */
|
||||||
@ -116,12 +116,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
|
|||||||
#ifdef HAVE_SIGNAL_H
|
#ifdef HAVE_SIGNAL_H
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_UTIME_H
|
|
||||||
#include <utime.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_SYS_UTIME_H
|
|
||||||
#include <sys/utime.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_SYS_MMAN_H
|
#ifdef HAVE_SYS_MMAN_H
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
@ -131,12 +125,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt)
|
|||||||
#ifdef HAVE_SYS_FILE_H
|
#ifdef HAVE_SYS_FILE_H
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef TOR_UNIT_TESTS
|
|
||||||
#if !defined(HAVE_USLEEP) && defined(HAVE_SYS_SELECT_H)
|
|
||||||
/* as fallback implementation for tor_sleep_msec */
|
|
||||||
#include <sys/select.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "torlog.h"
|
#include "torlog.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -2836,53 +2824,6 @@ compute_num_cpus(void)
|
|||||||
return num_cpus;
|
return num_cpus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set *timeval to the current time of day. On error, log and terminate.
|
|
||||||
* (Same as gettimeofday(timeval,NULL), but never returns -1.)
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
tor_gettimeofday(struct timeval *timeval)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
/* Epoch bias copied from perl: number of units between windows epoch and
|
|
||||||
* Unix epoch. */
|
|
||||||
#define EPOCH_BIAS U64_LITERAL(116444736000000000)
|
|
||||||
#define UNITS_PER_SEC U64_LITERAL(10000000)
|
|
||||||
#define USEC_PER_SEC U64_LITERAL(1000000)
|
|
||||||
#define UNITS_PER_USEC U64_LITERAL(10)
|
|
||||||
union {
|
|
||||||
uint64_t ft_64;
|
|
||||||
FILETIME ft_ft;
|
|
||||||
} ft;
|
|
||||||
/* number of 100-nsec units since Jan 1, 1601 */
|
|
||||||
GetSystemTimeAsFileTime(&ft.ft_ft);
|
|
||||||
if (ft.ft_64 < EPOCH_BIAS) {
|
|
||||||
/* LCOV_EXCL_START */
|
|
||||||
log_err(LD_GENERAL,"System time is before 1970; failing.");
|
|
||||||
exit(1);
|
|
||||||
/* LCOV_EXCL_STOP */
|
|
||||||
}
|
|
||||||
ft.ft_64 -= EPOCH_BIAS;
|
|
||||||
timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC);
|
|
||||||
timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC);
|
|
||||||
#elif defined(HAVE_GETTIMEOFDAY)
|
|
||||||
if (gettimeofday(timeval, NULL)) {
|
|
||||||
/* LCOV_EXCL_START */
|
|
||||||
log_err(LD_GENERAL,"gettimeofday failed.");
|
|
||||||
/* If gettimeofday dies, we have either given a bad timezone (we didn't),
|
|
||||||
or segfaulted.*/
|
|
||||||
exit(1);
|
|
||||||
/* LCOV_EXCL_STOP */
|
|
||||||
}
|
|
||||||
#elif defined(HAVE_FTIME)
|
|
||||||
struct timeb tb;
|
|
||||||
ftime(&tb);
|
|
||||||
timeval->tv_sec = tb.time;
|
|
||||||
timeval->tv_usec = tb.millitm * 1000;
|
|
||||||
#else
|
|
||||||
#error "No way to get time."
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
/** Defined iff we need to add locks when defining fake versions of reentrant
|
/** Defined iff we need to add locks when defining fake versions of reentrant
|
||||||
@ -3441,26 +3382,6 @@ get_total_system_memory(size_t *mem_out)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TOR_UNIT_TESTS
|
|
||||||
/** Delay for <b>msec</b> 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
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b>
|
/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b>
|
||||||
* bytes of passphrase into <b>output</b>. Return the number of bytes in
|
* bytes of passphrase into <b>output</b>. Return the number of bytes in
|
||||||
* the passphrase, excluding terminating NUL.
|
* the passphrase, excluding terminating NUL.
|
||||||
|
@ -42,6 +42,8 @@
|
|||||||
#include <netinet6/in6.h>
|
#include <netinet6/in6.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "compat_time.h"
|
||||||
|
|
||||||
#if defined(__has_feature)
|
#if defined(__has_feature)
|
||||||
# if __has_feature(address_sanitizer)
|
# if __has_feature(address_sanitizer)
|
||||||
/* Some of the fancy glibc strcmp() macros include references to memory that
|
/* Some of the fancy glibc strcmp() macros include references to memory that
|
||||||
@ -379,15 +381,6 @@ const char *tor_fix_source_file(const char *fname);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ===== Time compatibility */
|
/* ===== Time compatibility */
|
||||||
#if !defined(HAVE_GETTIMEOFDAY) && !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
|
|
||||||
|
|
||||||
void tor_gettimeofday(struct timeval *timeval);
|
|
||||||
|
|
||||||
struct tm *tor_localtime_r(const time_t *timep, struct tm *result);
|
struct tm *tor_localtime_r(const time_t *timep, struct tm *result);
|
||||||
struct tm *tor_gmtime_r(const time_t *timep, struct tm *result);
|
struct tm *tor_gmtime_r(const time_t *timep, struct tm *result);
|
||||||
@ -737,10 +730,6 @@ char *format_win32_error(DWORD err);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TOR_UNIT_TESTS
|
|
||||||
void tor_sleep_msec(int msec);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef COMPAT_PRIVATE
|
#ifdef COMPAT_PRIVATE
|
||||||
#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS)
|
#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS)
|
||||||
#define NEED_ERSATZ_SOCKETPAIR
|
#define NEED_ERSATZ_SOCKETPAIR
|
||||||
|
@ -388,33 +388,3 @@ tor_gettimeofday_cache_set(const struct timeval *tv)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* As tor_gettimeofday_cached, but can never move backwards in time.
|
|
||||||
*
|
|
||||||
* The returned value may diverge from wall-clock time, since wall-clock time
|
|
||||||
* can trivially be adjusted backwards, and this can't. Don't mix wall-clock
|
|
||||||
* time with these values in the same calculation.
|
|
||||||
*
|
|
||||||
* Depending on implementation, this function may or may not "smooth out" huge
|
|
||||||
* jumps forward in wall-clock time. It may or may not keep its results
|
|
||||||
* advancing forward (as opposed to stalling) if the wall-clock time goes
|
|
||||||
* backwards. The current implementation does neither of of these.
|
|
||||||
*
|
|
||||||
* This function is not thread-safe; do not call it outside the main thread.
|
|
||||||
*
|
|
||||||
* In future versions of Tor, this may return a time does not have its
|
|
||||||
* origin at the Unix epoch.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
tor_gettimeofday_cached_monotonic(struct timeval *tv)
|
|
||||||
{
|
|
||||||
struct timeval last_tv = { 0, 0 };
|
|
||||||
|
|
||||||
tor_gettimeofday_cached(tv);
|
|
||||||
if (timercmp(tv, &last_tv, OP_LT)) {
|
|
||||||
memcpy(tv, &last_tv, sizeof(struct timeval));
|
|
||||||
} else {
|
|
||||||
memcpy(&last_tv, tv, sizeof(struct timeval));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -70,7 +70,6 @@ void tor_gettimeofday_cache_clear(void);
|
|||||||
#ifdef TOR_UNIT_TESTS
|
#ifdef TOR_UNIT_TESTS
|
||||||
void tor_gettimeofday_cache_set(const struct timeval *tv);
|
void tor_gettimeofday_cache_set(const struct timeval *tv);
|
||||||
#endif
|
#endif
|
||||||
void tor_gettimeofday_cached_monotonic(struct timeval *tv);
|
|
||||||
|
|
||||||
#ifdef COMPAT_LIBEVENT_PRIVATE
|
#ifdef COMPAT_LIBEVENT_PRIVATE
|
||||||
|
|
||||||
|
513
src/common/compat_time.c
Normal file
513
src/common/compat_time.c
Normal file
@ -0,0 +1,513 @@
|
|||||||
|
/* Copyright (c) 2003-2004, Roger Dingledine
|
||||||
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||||
|
* Copyright (c) 2007-2016, 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 "compat.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_TYPES_H
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#ifdef TOR_UNIT_TESTS
|
||||||
|
#if !defined(HAVE_USLEEP) && defined(HAVE_SYS_SELECT_H)
|
||||||
|
/* as fallback implementation for tor_sleep_msec */
|
||||||
|
#include <sys/select.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "torlog.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "container.h"
|
||||||
|
|
||||||
|
#ifndef HAVE_GETTIMEOFDAY
|
||||||
|
#ifdef HAVE_FTIME
|
||||||
|
#include <sys/timeb.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TOR_UNIT_TESTS
|
||||||
|
/** Delay for <b>msec</b> 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
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Set *timeval to the current time of day. On error, log and terminate.
|
||||||
|
* (Same as gettimeofday(timeval,NULL), but never returns -1.)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
tor_gettimeofday(struct timeval *timeval)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* Epoch bias copied from perl: number of units between windows epoch and
|
||||||
|
* Unix epoch. */
|
||||||
|
#define EPOCH_BIAS U64_LITERAL(116444736000000000)
|
||||||
|
#define UNITS_PER_SEC U64_LITERAL(10000000)
|
||||||
|
#define USEC_PER_SEC U64_LITERAL(1000000)
|
||||||
|
#define UNITS_PER_USEC U64_LITERAL(10)
|
||||||
|
union {
|
||||||
|
uint64_t ft_64;
|
||||||
|
FILETIME ft_ft;
|
||||||
|
} ft;
|
||||||
|
/* number of 100-nsec units since Jan 1, 1601 */
|
||||||
|
GetSystemTimeAsFileTime(&ft.ft_ft);
|
||||||
|
if (ft.ft_64 < EPOCH_BIAS) {
|
||||||
|
/* LCOV_EXCL_START */
|
||||||
|
log_err(LD_GENERAL,"System time is before 1970; failing.");
|
||||||
|
exit(1);
|
||||||
|
/* LCOV_EXCL_STOP */
|
||||||
|
}
|
||||||
|
ft.ft_64 -= EPOCH_BIAS;
|
||||||
|
timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC);
|
||||||
|
timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC);
|
||||||
|
#elif defined(HAVE_GETTIMEOFDAY)
|
||||||
|
if (gettimeofday(timeval, NULL)) {
|
||||||
|
/* LCOV_EXCL_START */
|
||||||
|
log_err(LD_GENERAL,"gettimeofday failed.");
|
||||||
|
/* If gettimeofday dies, we have either given a bad timezone (we didn't),
|
||||||
|
or segfaulted.*/
|
||||||
|
exit(1);
|
||||||
|
/* LCOV_EXCL_STOP */
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_FTIME)
|
||||||
|
struct timeb tb;
|
||||||
|
ftime(&tb);
|
||||||
|
timeval->tv_sec = tb.time;
|
||||||
|
timeval->tv_usec = tb.millitm * 1000;
|
||||||
|
#else
|
||||||
|
#error "No way to get time."
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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;
|
||||||
|
|
||||||
|
/* "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
|
||||||
|
|
||||||
|
#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, <))) {
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
/** Initialized on startup: tells is how to convert from ticks to
|
||||||
|
* nanoseconds.
|
||||||
|
*/
|
||||||
|
static struct mach_timebase_info mach_time_info;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set "out" to the most recent monotonic time value
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
monotime_get(monotime_t *out)
|
||||||
|
{
|
||||||
|
out->abstime_ = mach_absolute_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the number of nanoseconds between <b>start</b> and <b>end</b>.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end of "__APPLE__" */
|
||||||
|
#elif defined(HAVE_CLOCK_GETTIME)
|
||||||
|
|
||||||
|
static void
|
||||||
|
monotime_init_internal(void)
|
||||||
|
{
|
||||||
|
/* no action needed. */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
monotime_get(monotime_t *out)
|
||||||
|
{
|
||||||
|
int r = clock_gettime(CLOCK_MONOTONIC, &out->ts_);
|
||||||
|
tor_assert(r == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CLOCK_MONOTONIC_COARSE
|
||||||
|
void
|
||||||
|
monotime_coarse_get(monotime_coarse_t *out)
|
||||||
|
{
|
||||||
|
int r = clock_gettime(CLOCK_MONOTONIC_COARSE, &out->ts_);
|
||||||
|
tor_assert(r == 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end of "HAVE_CLOCK_GETTIME" */
|
||||||
|
#elif defined (_WIN32)
|
||||||
|
|
||||||
|
/** Result of QueryPerformanceFrequency, as an int64_t. */
|
||||||
|
static int64_t ticks_per_second = 0;
|
||||||
|
|
||||||
|
/** 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);
|
||||||
|
ticks_per_second = li.QuadPart;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
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 * ONE_BILLION) / ticks_per_second;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end of "MONOTIME_USING_GETTIMEOFDAY" */
|
||||||
|
#else
|
||||||
|
#error "No way to implement monotonic timers."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static monotime_t initialized_at;
|
||||||
|
#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT
|
||||||
|
static monotime_coarse_t initialized_at_coarse;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_get(&initialized_at);
|
||||||
|
#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT
|
||||||
|
monotime_coarse_get(&initialized_at_coarse);
|
||||||
|
#endif
|
||||||
|
monotime_initialized = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif
|
150
src/common/compat_time.h
Normal file
150
src/common/compat_time.h
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/* Copyright (c) 2003-2004, Roger Dingledine
|
||||||
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||||
|
* Copyright (c) 2007-2016, 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"
|
||||||
|
|
||||||
|
#if defined(HAVE_CLOCK_GETTIME)
|
||||||
|
/* to ensure definition of CLOCK_MONOTONIC_COARSE if it's there */
|
||||||
|
#include <time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(HAVE_GETTIMEOFDAY) && !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
|
||||||
|
|
||||||
|
/** 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
|
||||||
|
} monotime_t;
|
||||||
|
|
||||||
|
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC_COARSE)
|
||||||
|
#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;
|
||||||
|
#else
|
||||||
|
#define monotime_coarse_t monotime_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the timing subsystem. This function is idempotent.
|
||||||
|
*/
|
||||||
|
void monotime_init(void);
|
||||||
|
/**
|
||||||
|
* Set <b>out</b> to the current time.
|
||||||
|
*/
|
||||||
|
void monotime_get(monotime_t *out);
|
||||||
|
/**
|
||||||
|
* Return the number of nanoseconds between <b>start</b> and <b>end</b>.
|
||||||
|
*/
|
||||||
|
int64_t monotime_diff_nsec(const monotime_t *start, const monotime_t *end);
|
||||||
|
/**
|
||||||
|
* Return the number of microseconds between <b>start</b> and <b>end</b>.
|
||||||
|
*/
|
||||||
|
int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end);
|
||||||
|
/**
|
||||||
|
* Return the number of milliseconds between <b>start</b> and <b>end</b>.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
|
||||||
|
#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT)
|
||||||
|
/**
|
||||||
|
* Set <b>out</b> 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
|
||||||
|
#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
|
||||||
|
|
||||||
|
#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);
|
||||||
|
#else
|
||||||
|
#define monotime_coarse_diff_nsec monotime_diff_nsec
|
||||||
|
#define monotime_coarse_diff_usec monotime_diff_usec
|
||||||
|
#define monotime_coarse_diff_msec monotime_diff_msec
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void tor_gettimeofday(struct timeval *timeval);
|
||||||
|
|
||||||
|
#ifdef TOR_UNIT_TESTS
|
||||||
|
void tor_sleep_msec(int msec);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -83,6 +83,7 @@ LIBOR_A_SRC = \
|
|||||||
src/common/backtrace.c \
|
src/common/backtrace.c \
|
||||||
src/common/compat.c \
|
src/common/compat.c \
|
||||||
src/common/compat_threads.c \
|
src/common/compat_threads.c \
|
||||||
|
src/common/compat_time.c \
|
||||||
src/common/container.c \
|
src/common/container.c \
|
||||||
src/common/log.c \
|
src/common/log.c \
|
||||||
src/common/memarea.c \
|
src/common/memarea.c \
|
||||||
|
@ -18,9 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Notes:
|
/* Notes:
|
||||||
*
|
|
||||||
* The use of tor_gettimeofday_cached_monotonic() is kind of ugly. It would
|
|
||||||
* be neat to fix it.
|
|
||||||
*
|
*
|
||||||
* Having a way to free all timers on shutdown would free people from the
|
* Having a way to free all timers on shutdown would free people from the
|
||||||
* need to track them. Not sure if that's clever though.
|
* need to track them. Not sure if that's clever though.
|
||||||
@ -72,6 +69,8 @@ struct timeout_cb {
|
|||||||
static struct timeouts *global_timeouts = NULL;
|
static struct timeouts *global_timeouts = NULL;
|
||||||
static struct event *global_timer_event = NULL;
|
static struct event *global_timer_event = NULL;
|
||||||
|
|
||||||
|
static monotime_t start_of_time;
|
||||||
|
|
||||||
/** We need to choose this value carefully. Because we're using timer wheels,
|
/** We need to choose this value carefully. Because we're using timer wheels,
|
||||||
* it actually costs us to have extra resolution we don't use. So for now,
|
* it actually costs us to have extra resolution we don't use. So for now,
|
||||||
* I'm going to define our resolution as .1 msec, and hope that's good enough.
|
* I'm going to define our resolution as .1 msec, and hope that's good enough.
|
||||||
@ -95,9 +94,8 @@ static struct event *global_timer_event = NULL;
|
|||||||
/**
|
/**
|
||||||
* Convert the timeval in <b>tv</b> to a timeout_t, and return it.
|
* Convert the timeval in <b>tv</b> to a timeout_t, and return it.
|
||||||
*
|
*
|
||||||
* The output resolution is set by USEC_PER_TICK, and the time corresponding
|
* The output resolution is set by USEC_PER_TICK. Only use this to convert
|
||||||
* to 0 is the same as the time corresponding to 0 from
|
* delays to number of ticks; the time represented by 0 is undefined.
|
||||||
* tor_gettimeofday_cached_monotonic().
|
|
||||||
*/
|
*/
|
||||||
static timeout_t
|
static timeout_t
|
||||||
tv_to_timeout(const struct timeval *tv)
|
tv_to_timeout(const struct timeval *tv)
|
||||||
@ -108,7 +106,8 @@ tv_to_timeout(const struct timeval *tv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the timeout in <b>t</b> to a timeval in <b>tv_out</b>
|
* Convert the timeout in <b>t</b> to a timeval in <b>tv_out</b>. Only
|
||||||
|
* use this for delays, not absolute times.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
timeout_to_tv(timeout_t t, struct timeval *tv_out)
|
timeout_to_tv(timeout_t t, struct timeval *tv_out)
|
||||||
@ -122,12 +121,10 @@ timeout_to_tv(timeout_t t, struct timeval *tv_out)
|
|||||||
* Update the timer <b>tv</b> to the current time in <b>tv</b>.
|
* Update the timer <b>tv</b> to the current time in <b>tv</b>.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
timer_advance_to_cur_time(const struct timeval *tv)
|
timer_advance_to_cur_time(const monotime_t *now)
|
||||||
{
|
{
|
||||||
timeout_t cur_tick = tv_to_timeout(tv);
|
timeout_t cur_tick = CEIL_DIV(monotime_diff_usec(&start_of_time, now),
|
||||||
if (BUG(cur_tick < timeouts_get_curtime(global_timeouts))) {
|
USEC_PER_TICK);
|
||||||
cur_tick = timeouts_get_curtime(global_timeouts); // LCOV_EXCL_LINE
|
|
||||||
}
|
|
||||||
timeouts_update(global_timeouts, cur_tick);
|
timeouts_update(global_timeouts, cur_tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,11 +135,12 @@ timer_advance_to_cur_time(const struct timeval *tv)
|
|||||||
static void
|
static void
|
||||||
libevent_timer_reschedule(void)
|
libevent_timer_reschedule(void)
|
||||||
{
|
{
|
||||||
struct timeval now;
|
monotime_t now;
|
||||||
tor_gettimeofday_cached_monotonic(&now);
|
monotime_get(&now);
|
||||||
timer_advance_to_cur_time(&now);
|
timer_advance_to_cur_time(&now);
|
||||||
|
|
||||||
timeout_t delay = timeouts_timeout(global_timeouts);
|
timeout_t delay = timeouts_timeout(global_timeouts);
|
||||||
|
|
||||||
struct timeval d;
|
struct timeval d;
|
||||||
if (delay > MIN_CHECK_TICKS)
|
if (delay > MIN_CHECK_TICKS)
|
||||||
delay = MIN_CHECK_TICKS;
|
delay = MIN_CHECK_TICKS;
|
||||||
@ -161,9 +159,8 @@ libevent_timer_callback(evutil_socket_t fd, short what, void *arg)
|
|||||||
(void)what;
|
(void)what;
|
||||||
(void)arg;
|
(void)arg;
|
||||||
|
|
||||||
struct timeval now;
|
monotime_t now;
|
||||||
tor_gettimeofday_cache_clear();
|
monotime_get(&now);
|
||||||
tor_gettimeofday_cached_monotonic(&now);
|
|
||||||
timer_advance_to_cur_time(&now);
|
timer_advance_to_cur_time(&now);
|
||||||
|
|
||||||
tor_timer_t *t;
|
tor_timer_t *t;
|
||||||
@ -171,7 +168,6 @@ libevent_timer_callback(evutil_socket_t fd, short what, void *arg)
|
|||||||
t->callback.cb(t, t->callback.arg, &now);
|
t->callback.cb(t, t->callback.arg, &now);
|
||||||
}
|
}
|
||||||
|
|
||||||
tor_gettimeofday_cache_clear();
|
|
||||||
libevent_timer_reschedule();
|
libevent_timer_reschedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,6 +190,9 @@ timers_initialize(void)
|
|||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
monotime_init();
|
||||||
|
monotime_get(&start_of_time);
|
||||||
|
|
||||||
struct event *timer_event;
|
struct event *timer_event;
|
||||||
timer_event = tor_event_new(tor_libevent_get_base(),
|
timer_event = tor_event_new(tor_libevent_get_base(),
|
||||||
-1, 0, libevent_timer_callback, NULL);
|
-1, 0, libevent_timer_callback, NULL);
|
||||||
@ -256,24 +255,25 @@ timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule the timer t to fire at the current time plus a delay of <b>tv</b>.
|
* Schedule the timer t to fire at the current time plus a delay of
|
||||||
* All times are relative to tor_gettimeofday_cached_monotonic.
|
* <b>delay</b> microseconds. All times are relative to monotime_get().
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
timer_schedule(tor_timer_t *t, const struct timeval *tv)
|
timer_schedule(tor_timer_t *t, const struct timeval *tv)
|
||||||
{
|
{
|
||||||
const timeout_t when = tv_to_timeout(tv);
|
const timeout_t delay = tv_to_timeout(tv);
|
||||||
struct timeval now;
|
|
||||||
tor_gettimeofday_cached_monotonic(&now);
|
monotime_t now;
|
||||||
|
monotime_get(&now);
|
||||||
timer_advance_to_cur_time(&now);
|
timer_advance_to_cur_time(&now);
|
||||||
|
|
||||||
/* Take the old timeout value. */
|
/* Take the old timeout value. */
|
||||||
timeout_t to = timeouts_timeout(global_timeouts);
|
timeout_t to = timeouts_timeout(global_timeouts);
|
||||||
|
|
||||||
timeouts_add(global_timeouts, t, when);
|
timeouts_add(global_timeouts, t, delay);
|
||||||
|
|
||||||
/* Should we update the libevent timer? */
|
/* Should we update the libevent timer? */
|
||||||
if (to <= when) {
|
if (to <= delay) {
|
||||||
return; /* we're already going to fire before this timer would trigger. */
|
return; /* we're already going to fire before this timer would trigger. */
|
||||||
}
|
}
|
||||||
libevent_timer_reschedule();
|
libevent_timer_reschedule();
|
||||||
|
@ -7,8 +7,9 @@
|
|||||||
#include "orconfig.h"
|
#include "orconfig.h"
|
||||||
#include "testsupport.h"
|
#include "testsupport.h"
|
||||||
|
|
||||||
|
struct monotime_t;
|
||||||
typedef struct timeout tor_timer_t;
|
typedef struct timeout tor_timer_t;
|
||||||
typedef void (*timer_cb_fn_t)(tor_timer_t *, void *, const struct timeval *);
|
typedef void (*timer_cb_fn_t)(tor_timer_t *, void *, const struct monotime_t *);
|
||||||
tor_timer_t *timer_new(timer_cb_fn_t cb, void *arg);
|
tor_timer_t *timer_new(timer_cb_fn_t cb, void *arg);
|
||||||
void timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg);
|
void timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg);
|
||||||
void timer_schedule(tor_timer_t *t, const struct timeval *delay);
|
void timer_schedule(tor_timer_t *t, const struct timeval *delay);
|
||||||
|
@ -405,7 +405,7 @@ static chunk_t *
|
|||||||
buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
|
buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
|
||||||
{
|
{
|
||||||
chunk_t *chunk;
|
chunk_t *chunk;
|
||||||
struct timeval now;
|
|
||||||
if (CHUNK_ALLOC_SIZE(capacity) < buf->default_chunk_size) {
|
if (CHUNK_ALLOC_SIZE(capacity) < buf->default_chunk_size) {
|
||||||
chunk = chunk_new_with_alloc_size(buf->default_chunk_size);
|
chunk = chunk_new_with_alloc_size(buf->default_chunk_size);
|
||||||
} else if (capped && CHUNK_ALLOC_SIZE(capacity) > MAX_CHUNK_ALLOC) {
|
} else if (capped && CHUNK_ALLOC_SIZE(capacity) > MAX_CHUNK_ALLOC) {
|
||||||
@ -414,8 +414,7 @@ buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
|
|||||||
chunk = chunk_new_with_alloc_size(preferred_chunk_size(capacity));
|
chunk = chunk_new_with_alloc_size(preferred_chunk_size(capacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
tor_gettimeofday_cached_monotonic(&now);
|
chunk->inserted_time = (uint32_t)monotime_coarse_absolute_msec();
|
||||||
chunk->inserted_time = (uint32_t)tv_to_msec(&now);
|
|
||||||
|
|
||||||
if (buf->tail) {
|
if (buf->tail) {
|
||||||
tor_assert(buf->head);
|
tor_assert(buf->head);
|
||||||
@ -430,8 +429,8 @@ buf_add_chunk_with_capacity(buf_t *buf, size_t capacity, int capped)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Return the age of the oldest chunk in the buffer <b>buf</b>, in
|
/** Return the age of the oldest chunk in the buffer <b>buf</b>, in
|
||||||
* milliseconds. Requires the current time, in truncated milliseconds since
|
* milliseconds. Requires the current monotonic time, in truncated msec,
|
||||||
* the epoch, as its input <b>now</b>.
|
* as its input <b>now</b>.
|
||||||
*/
|
*/
|
||||||
uint32_t
|
uint32_t
|
||||||
buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now)
|
buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now)
|
||||||
|
@ -2015,7 +2015,7 @@ circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
|
|||||||
|
|
||||||
/** Return the age in milliseconds of the oldest buffer chunk on <b>conn</b>,
|
/** Return the age in milliseconds of the oldest buffer chunk on <b>conn</b>,
|
||||||
* where age is taken in milliseconds before the time <b>now</b> (in truncated
|
* where age is taken in milliseconds before the time <b>now</b> (in truncated
|
||||||
* milliseconds since the epoch). If the connection has no data, treat
|
* absolute monotonic msec). If the connection has no data, treat
|
||||||
* it as having age zero.
|
* it as having age zero.
|
||||||
**/
|
**/
|
||||||
static uint32_t
|
static uint32_t
|
||||||
@ -2138,7 +2138,6 @@ circuits_handle_oom(size_t current_allocation)
|
|||||||
size_t mem_recovered=0;
|
size_t mem_recovered=0;
|
||||||
int n_circuits_killed=0;
|
int n_circuits_killed=0;
|
||||||
int n_dirconns_killed=0;
|
int n_dirconns_killed=0;
|
||||||
struct timeval now;
|
|
||||||
uint32_t now_ms;
|
uint32_t now_ms;
|
||||||
log_notice(LD_GENERAL, "We're low on memory. Killing circuits with "
|
log_notice(LD_GENERAL, "We're low on memory. Killing circuits with "
|
||||||
"over-long queues. (This behavior is controlled by "
|
"over-long queues. (This behavior is controlled by "
|
||||||
@ -2152,8 +2151,7 @@ circuits_handle_oom(size_t current_allocation)
|
|||||||
mem_to_recover = current_allocation - mem_target;
|
mem_to_recover = current_allocation - mem_target;
|
||||||
}
|
}
|
||||||
|
|
||||||
tor_gettimeofday_cached_monotonic(&now);
|
now_ms = (uint32_t)monotime_coarse_absolute_msec();
|
||||||
now_ms = (uint32_t)tv_to_msec(&now);
|
|
||||||
|
|
||||||
circlist = circuit_get_global_list();
|
circlist = circuit_get_global_list();
|
||||||
SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
|
SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
|
||||||
|
@ -3646,6 +3646,8 @@ tor_main(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
monotime_init();
|
||||||
|
|
||||||
switch (get_options()->command) {
|
switch (get_options()->command) {
|
||||||
case CMD_RUN_TOR:
|
case CMD_RUN_TOR:
|
||||||
#ifdef NT_SERVICE
|
#ifdef NT_SERVICE
|
||||||
|
@ -2320,14 +2320,12 @@ cell_queue_append_packed_copy(circuit_t *circ, cell_queue_t *queue,
|
|||||||
int exitward, const cell_t *cell,
|
int exitward, const cell_t *cell,
|
||||||
int wide_circ_ids, int use_stats)
|
int wide_circ_ids, int use_stats)
|
||||||
{
|
{
|
||||||
struct timeval now;
|
|
||||||
packed_cell_t *copy = packed_cell_copy(cell, wide_circ_ids);
|
packed_cell_t *copy = packed_cell_copy(cell, wide_circ_ids);
|
||||||
(void)circ;
|
(void)circ;
|
||||||
(void)exitward;
|
(void)exitward;
|
||||||
(void)use_stats;
|
(void)use_stats;
|
||||||
tor_gettimeofday_cached_monotonic(&now);
|
|
||||||
|
|
||||||
copy->inserted_time = (uint32_t)tv_to_msec(&now);
|
copy->inserted_time = (uint32_t) monotime_coarse_absolute_msec();
|
||||||
|
|
||||||
cell_queue_append(queue, copy);
|
cell_queue_append(queue, copy);
|
||||||
}
|
}
|
||||||
|
@ -28,15 +28,26 @@ static tor_timer_t *timers[N_TIMERS] = {NULL};
|
|||||||
static int n_active_timers = 0;
|
static int n_active_timers = 0;
|
||||||
static int n_fired = 0;
|
static int n_fired = 0;
|
||||||
|
|
||||||
|
static monotime_t started_at;
|
||||||
|
static int64_t delay_usec[N_TIMERS];
|
||||||
|
static int64_t diffs_mono_usec[N_TIMERS];
|
||||||
|
|
||||||
static void
|
static void
|
||||||
timer_cb(tor_timer_t *t, void *arg, const struct timeval *now)
|
timer_cb(tor_timer_t *t, void *arg, const monotime_t *now_mono)
|
||||||
{
|
{
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
tor_gettimeofday(&now);
|
||||||
tor_timer_t **t_ptr = arg;
|
tor_timer_t **t_ptr = arg;
|
||||||
tor_assert(*t_ptr == t);
|
tor_assert(*t_ptr == t);
|
||||||
int idx = (int) (t_ptr - timers);
|
int idx = (int) (t_ptr - timers);
|
||||||
++fired[idx];
|
++fired[idx];
|
||||||
timersub(now, &fire_at[idx], &difference[idx]);
|
timersub(&now, &fire_at[idx], &difference[idx]);
|
||||||
|
diffs_mono_usec[idx] =
|
||||||
|
monotime_diff_usec(&started_at, now_mono) -
|
||||||
|
delay_usec[idx];
|
||||||
++n_fired;
|
++n_fired;
|
||||||
|
|
||||||
// printf("%d / %d\n",n_fired, N_TIMERS);
|
// printf("%d / %d\n",n_fired, N_TIMERS);
|
||||||
if (n_fired == n_active_timers) {
|
if (n_fired == n_active_timers) {
|
||||||
event_base_loopbreak(tor_libevent_get_base());
|
event_base_loopbreak(tor_libevent_get_base());
|
||||||
@ -57,10 +68,12 @@ main(int argc, char **argv)
|
|||||||
int ret;
|
int ret;
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
tor_gettimeofday(&now);
|
tor_gettimeofday(&now);
|
||||||
|
monotime_get(&started_at);
|
||||||
for (i = 0; i < N_TIMERS; ++i) {
|
for (i = 0; i < N_TIMERS; ++i) {
|
||||||
struct timeval delay;
|
struct timeval delay;
|
||||||
delay.tv_sec = crypto_rand_int_range(0,MAX_DURATION);
|
delay.tv_sec = crypto_rand_int_range(0,MAX_DURATION);
|
||||||
delay.tv_usec = crypto_rand_int_range(0,1000000);
|
delay.tv_usec = crypto_rand_int_range(0,1000000);
|
||||||
|
delay_usec[i] = delay.tv_sec * 1000000 + delay.tv_usec;
|
||||||
timeradd(&now, &delay, &fire_at[i]);
|
timeradd(&now, &delay, &fire_at[i]);
|
||||||
timers[i] = timer_new(timer_cb, &timers[i]);
|
timers[i] = timer_new(timer_cb, &timers[i]);
|
||||||
timer_schedule(timers[i], &delay);
|
timer_schedule(timers[i], &delay);
|
||||||
@ -88,7 +101,8 @@ main(int argc, char **argv)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tor_assert(fired[i] == 1);
|
tor_assert(fired[i] == 1);
|
||||||
int64_t diff = difference[i].tv_usec + difference[i].tv_sec * 1000000;
|
//int64_t diff = difference[i].tv_usec + difference[i].tv_sec * 1000000;
|
||||||
|
int64_t diff = diffs_mono_usec[i];
|
||||||
total_difference += diff;
|
total_difference += diff;
|
||||||
total_square_difference += diff*diff;
|
total_square_difference += diff*diff;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "orconfig.h"
|
#include "orconfig.h"
|
||||||
#define COMPAT_PRIVATE
|
#define COMPAT_PRIVATE
|
||||||
|
#define COMPAT_TIME_PRIVATE
|
||||||
#define CONTROL_PRIVATE
|
#define CONTROL_PRIVATE
|
||||||
#define UTIL_PRIVATE
|
#define UTIL_PRIVATE
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
@ -5285,6 +5286,128 @@ test_util_calloc_check(void *arg)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_util_monotonic_time(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
monotime_t mt1, mt2;
|
||||||
|
monotime_coarse_t mtc1, mtc2;
|
||||||
|
uint64_t nsec1, nsec2, usec1, msec1;
|
||||||
|
uint64_t nsecc1, nsecc2, usecc1, msecc1;
|
||||||
|
|
||||||
|
monotime_get(&mt1);
|
||||||
|
monotime_coarse_get(&mtc1);
|
||||||
|
nsec1 = monotime_absolute_nsec();
|
||||||
|
usec1 = monotime_absolute_usec();
|
||||||
|
msec1 = monotime_absolute_msec();
|
||||||
|
nsecc1 = monotime_coarse_absolute_nsec();
|
||||||
|
usecc1 = monotime_coarse_absolute_usec();
|
||||||
|
msecc1 = monotime_coarse_absolute_msec();
|
||||||
|
|
||||||
|
tor_sleep_msec(200);
|
||||||
|
|
||||||
|
monotime_get(&mt2);
|
||||||
|
monotime_coarse_get(&mtc2);
|
||||||
|
nsec2 = monotime_absolute_nsec();
|
||||||
|
nsecc2 = monotime_coarse_absolute_nsec();
|
||||||
|
|
||||||
|
/* We need to be a little careful here since we don't know the system load.
|
||||||
|
*/
|
||||||
|
tt_i64_op(monotime_diff_msec(&mt1, &mt2), OP_GE, 175);
|
||||||
|
tt_i64_op(monotime_diff_msec(&mt1, &mt2), OP_LT, 1000);
|
||||||
|
tt_i64_op(monotime_coarse_diff_msec(&mtc1, &mtc2), OP_GE, 125);
|
||||||
|
tt_i64_op(monotime_coarse_diff_msec(&mtc1, &mtc2), OP_LT, 1000);
|
||||||
|
tt_u64_op(nsec2-nsec1, OP_GE, 175000000);
|
||||||
|
tt_u64_op(nsec2-nsec1, OP_LT, 1000000000);
|
||||||
|
tt_u64_op(nsecc2-nsecc1, OP_GE, 125000000);
|
||||||
|
tt_u64_op(nsecc2-nsecc1, OP_LT, 1000000000);
|
||||||
|
|
||||||
|
tt_u64_op(msec1, OP_GE, nsec1 / 1000000);
|
||||||
|
tt_u64_op(usec1, OP_GE, nsec1 / 1000);
|
||||||
|
tt_u64_op(msecc1, OP_GE, nsecc1 / 1000000);
|
||||||
|
tt_u64_op(usecc1, OP_GE, nsecc1 / 1000);
|
||||||
|
tt_u64_op(msec1, OP_LE, nsec1 / 1000000 + 1);
|
||||||
|
tt_u64_op(usec1, OP_LE, nsec1 / 1000 +10);
|
||||||
|
tt_u64_op(msecc1, OP_LE, nsecc1 / 1000000 + 1);
|
||||||
|
tt_u64_op(usecc1, OP_LE, nsecc1 / 1000 + 10);
|
||||||
|
|
||||||
|
done:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_util_monotonic_time_ratchet(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
monotime_reset_ratchets_for_testing();
|
||||||
|
|
||||||
|
/* win32, performance counter ratchet. */
|
||||||
|
tt_i64_op(100, OP_EQ, ratchet_performance_counter(100));
|
||||||
|
tt_i64_op(101, OP_EQ, ratchet_performance_counter(101));
|
||||||
|
tt_i64_op(2000, OP_EQ, ratchet_performance_counter(2000));
|
||||||
|
tt_i64_op(2000, OP_EQ, ratchet_performance_counter(100));
|
||||||
|
tt_i64_op(2005, OP_EQ, ratchet_performance_counter(105));
|
||||||
|
tt_i64_op(3005, OP_EQ, ratchet_performance_counter(1105));
|
||||||
|
tt_i64_op(3005, OP_EQ, ratchet_performance_counter(1000));
|
||||||
|
tt_i64_op(3010, OP_EQ, ratchet_performance_counter(1005));
|
||||||
|
|
||||||
|
/* win32, GetTickCounts32 ratchet-and-rollover-detector. */
|
||||||
|
const int64_t R = ((int64_t)1) << 32;
|
||||||
|
tt_i64_op(5, OP_EQ, ratchet_coarse_performance_counter(5));
|
||||||
|
tt_i64_op(1000, OP_EQ, ratchet_coarse_performance_counter(1000));
|
||||||
|
tt_i64_op(5+R, OP_EQ, ratchet_coarse_performance_counter(5));
|
||||||
|
tt_i64_op(10+R, OP_EQ, ratchet_coarse_performance_counter(10));
|
||||||
|
tt_i64_op(4+R*2, OP_EQ, ratchet_coarse_performance_counter(4));
|
||||||
|
|
||||||
|
/* gettimeofday regular ratchet. */
|
||||||
|
struct timeval tv_in = {0,0}, tv_out;
|
||||||
|
tv_in.tv_usec = 9000;
|
||||||
|
|
||||||
|
ratchet_timeval(&tv_in, &tv_out);
|
||||||
|
tt_int_op(tv_out.tv_usec, OP_EQ, 9000);
|
||||||
|
tt_i64_op(tv_out.tv_sec, OP_EQ, 0);
|
||||||
|
|
||||||
|
tv_in.tv_sec = 1337;
|
||||||
|
tv_in.tv_usec = 0;
|
||||||
|
ratchet_timeval(&tv_in, &tv_out);
|
||||||
|
tt_int_op(tv_out.tv_usec, OP_EQ, 0);
|
||||||
|
tt_i64_op(tv_out.tv_sec, OP_EQ, 1337);
|
||||||
|
|
||||||
|
tv_in.tv_sec = 1336;
|
||||||
|
tv_in.tv_usec = 500000;
|
||||||
|
ratchet_timeval(&tv_in, &tv_out);
|
||||||
|
tt_int_op(tv_out.tv_usec, OP_EQ, 0);
|
||||||
|
tt_i64_op(tv_out.tv_sec, OP_EQ, 1337);
|
||||||
|
|
||||||
|
tv_in.tv_sec = 1337;
|
||||||
|
tv_in.tv_usec = 0;
|
||||||
|
ratchet_timeval(&tv_in, &tv_out);
|
||||||
|
tt_int_op(tv_out.tv_usec, OP_EQ, 500000);
|
||||||
|
tt_i64_op(tv_out.tv_sec, OP_EQ, 1337);
|
||||||
|
|
||||||
|
tv_in.tv_sec = 1337;
|
||||||
|
tv_in.tv_usec = 600000;
|
||||||
|
ratchet_timeval(&tv_in, &tv_out);
|
||||||
|
tt_int_op(tv_out.tv_usec, OP_EQ, 100000);
|
||||||
|
tt_i64_op(tv_out.tv_sec, OP_EQ, 1338);
|
||||||
|
|
||||||
|
tv_in.tv_sec = 1000;
|
||||||
|
tv_in.tv_usec = 1000;
|
||||||
|
ratchet_timeval(&tv_in, &tv_out);
|
||||||
|
tt_int_op(tv_out.tv_usec, OP_EQ, 100000);
|
||||||
|
tt_i64_op(tv_out.tv_sec, OP_EQ, 1338);
|
||||||
|
|
||||||
|
tv_in.tv_sec = 2000;
|
||||||
|
tv_in.tv_usec = 2000;
|
||||||
|
ratchet_timeval(&tv_in, &tv_out);
|
||||||
|
tt_int_op(tv_out.tv_usec, OP_EQ, 101000);
|
||||||
|
tt_i64_op(tv_out.tv_sec, OP_EQ, 2338);
|
||||||
|
|
||||||
|
done:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
#define UTIL_LEGACY(name) \
|
#define UTIL_LEGACY(name) \
|
||||||
{ #name, test_util_ ## name , 0, NULL, NULL }
|
{ #name, test_util_ ## name , 0, NULL, NULL }
|
||||||
|
|
||||||
@ -5373,6 +5496,8 @@ struct testcase_t util_tests[] = {
|
|||||||
UTIL_TEST(touch_file, 0),
|
UTIL_TEST(touch_file, 0),
|
||||||
UTIL_TEST_NO_WIN(pwdb, TT_FORK),
|
UTIL_TEST_NO_WIN(pwdb, TT_FORK),
|
||||||
UTIL_TEST(calloc_check, 0),
|
UTIL_TEST(calloc_check, 0),
|
||||||
|
UTIL_TEST(monotonic_time, 0),
|
||||||
|
UTIL_TEST(monotonic_time_ratchet, TT_FORK),
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user