










Tor时间模块位于src/lib/time/文件夹
这里的时间是指一个递增的计时器,每次获得的会是一个增加量
关于墙上时钟(wall clock)和递增时间(monotonic time)的更多解释
const subsys_fns_t sys_time = { .name = "time", /* Monotonic time depends on logging, and a lot of other modules depend on * monotonic time. */ .level = -80, .supported = true, .initialize = subsys_time_initialize, };
当系统不存在timeval时,会在这里重定义该类型
通常而言,该类型应该会定义于/usr/include/bits/types/struct_timeval.h
struct timeval { time_t tv_sec; unsigned int tv_usec; };
一般而言,该类型在模块外部不应该被修改,因为其结构定义的属性在不同环境都是不同的。也即对应的成员变量都是私有的
这里实际是重新封装了在不同平台上monotime的实现
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;
和monotime_t相似,该类型也是重新的封装,但是相对于monotime_t,monotime_coarse_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) && ... || ... */
该模块由于需要对不同平台进行不同的处理,因此大部分的代码都在使用各种宏定义来处理跨平台环境问题。这里单独选出一些代表性的函数为例
该函数用于初始化时间子系统
会首先初始化该平台相关内容,并将记录当前的monotime和monotime_coarse
/** * Initialize the timing subsystem. This function is idempotent. */ void monotime_init(void);
初始化一些平台相关的内容
mach_timebase_info()初始化mach_time_info,并计算每毫秒、纳秒有多少 tickclock_gettime()函数的环境下,会判断是否支持monotime_coarse,如果不支持,则会将其退化成monotimekernel32.dllstatic void monotime_init_internal(void)
mach_absolute_time()获取递增时间clock_gettime()函数的环境下,会使用clock_gettime(CLOCK_MONOTONIC, &out->ts_)获取递增时间QueryPerformanceCounter()及ratchet_performance_counter获取递增时间tor_gettimeofday()及ratchet_timeval()获取递增时间/** * Set <b>out</b> to the current time. */ void monotime_get(monotime_t *out);
在src/lib/time/compat_time.h中,有一份Q/A文档:
time模块?
monotime和monotime_coarse?
monotime可以得到更高的精度;使用monotime_coarse可以得到更好的性能表现monotime_coarse,monotime_t或monotime_coarse_t用于毫秒( msec )、微秒 ( usec ) 时间单元?
monotime_t和monotime_coarse_t会有更高的效率,但是可能会浪费更多的内存用于存储微秒、毫秒monotime_coarse的转换,并且保证在 32 位整数能保证 1 ~ 2 毫秒的精度,但是其缺点是该类型并不是一个自然存在的时间单位monotime_coarse的后端实现是什么?
monotime_coarse使用GetCount64()(或已过时的GetTickCount())实现。MSDN 生成精度保证在 10 ~ 16 毫秒范围内。存储monotime_coarse_t共使用 8 字节monotime_coarse使用mach_approximate_time()获得,并返回标准的 mongotime ,该精度没有文档明确说明,但是其实现是开源的,可以得知其是从内核更新的内存页读取数据,并且存储monotime_coarse_t共使用 8 字节monotime_coarse使用clock_gettime()和CLOCK_MONOTONIC_COARSE实现,并且函数会返回CLOCK_MONOTONIC。该实现使用 vdso 技巧来读取内核更新页面,并且精度是固定的。但是让然可以使用clock_getres()。在一些 linux desktop 中,生成精度为 1 毫秒,但是这个值取决于系统频率设置。存储monotime_coarse_t将使用 16 字节CLOCK_MONOTONIC_FASTmonotime的后端实现是什么?
monotime使用系统调用实现,在系统调用比较轻量的平台中,这么做效果很好,但是在系统调用繁琐的系统中则很吃亏QueryPerformanceCounter获取,并且存储monotime_t使用 8 字节mach_absolute_time获取,并且存储monotime_t使用 8 字节CLOCK_MONOTONIC获取,并且存储monotime_t使用 16 字节tv_nsec除以1000,并且纳秒存储在 32 位值中EVENT_BASE_FLAG_PRECISE_TIMER,最近的一些 libevents 也可以使用timerfd来获得更高的精度( Tor 没有设置该标志)此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。