libevent中的时间及相关的管理

libevent中的时间及相关的管理

在介绍时间之前,先说明几个与时间相关的函数及其用

1、基础

1.1 clock_gettime(精度比较高,ns级)

#include <time.h>
int clock_gettime(clockid_t clk_id, struct timespec *tp);

clk_id:检索和设置的clk_id指定的时钟时间

CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-10:0:0开始计时,中间时刻如果系统时间被用户改成其他,则对应的时间相应改变

CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响

CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间

CLOCK_THREAD_CPUTIME_ID:线程到当前代码系统CPU花费的时间

struct timespec结构表示为:

struct timespec
{
		time_t tv_sec;//秒
		long tv_nsec;//纳秒
};

1.2 ftimems级)

windows:

#include <sys/timeb.h>

void _ftime(struct _timeb *tp);

而在linux:

void ftime(struct timeb *tp);

结构体表示为:

struct timeb
{
	time_t time;//秒
	unsigned short millitm;//毫秒
	short timezone;
	short dstflag;
}

2、时间检测

在初始化是检测系统是不是支持monotonic,是通过调用clock_gettime来检测的,如果支持将use_monotonic设置为1,具体的实现为

static void
detect_monotonic(void)
{
#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
	struct timespec	ts;
	static int use_monotonic_initialized = 0;

	if (use_monotonic_initialized)
		return;

	if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
		use_monotonic = 1;

	use_monotonic_initialized = 1;
#endif
}

3、时间缓存

base中的tv_cache用来记录时间缓存,主要是为了防止频繁的调用系统函数来获取时间,而获取时间的调用为gettime,其代码为

static int
gettime(struct event_base *base, struct timeval *tp)
{
	EVENT_BASE_ASSERT_LOCKED(base);

	if (base->tv_cache.tv_sec) {   //时间缓存秒非0,直接将缓存值返回
		*tp = base->tv_cache;
		return (0);
	}

#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
	if (use_monotonic) {   //支持monotonic,用clock_gettime获取时间
		struct timespec	ts;

		if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
			return (-1);

		tp->tv_sec = ts.tv_sec;
		tp->tv_usec = ts.tv_nsec / 1000;
		if (base->last_updated_clock_diff + CLOCK_SYNC_INTERVAL
		    < ts.tv_sec) { //如果此次获取的时间与上次更新时间相关大于1秒,就更新base中的tv_clock_diff,并将last_updated_clock_diff设置为此次获取的时间
			struct timeval tv;
			evutil_gettimeofday(&tv,NULL);
			evutil_timersub(&tv, tp, &base->tv_clock_diff);
			base->last_updated_clock_diff = ts.tv_sec;
		}

		return (0);
	}
#endif

	return (evutil_gettimeofday(tp, NULL));
}
event_base_loop 主循环中,在处理分发事件前,总是将时间缓存清 0 ,分发后再更新时间缓存

while (!done) {
		...........................
		clear_time_cache(base);

		res = evsel->dispatch(base, tv_p);
		......................
		update_time_cache(base);
		.......................
}

4、时间校正

如果系统支持monotonic,就不需要校正,系统不支持monotonic,而用户可能会修改系统时间,将时间向前调,这时,就需要校正,由函数timeout_correct来完成

static void
timeout_correct(struct event_base *base, struct timeval *tv)
{
	/* Caller must hold th_base_lock. */
	struct event **pev;
	unsigned int size;
	struct timeval off;
	int i;

	if (use_monotonic)  //支持monotonic直接返回
		return;

	/* Check if time is running backwards */
	gettime(base, tv);  //获取当前时间

	if (evutil_timercmp(tv, &base->event_tv, >=)) {//时间不有向前调,将base的event_tv设置为当前时间,返回
		base->event_tv = *tv;
		return;
	}

	event_debug(("%s: time is running backwards, corrected",
		    __func__));
	evutil_timersub(&base->event_tv, tv, &off);  //计算时间差

	/*
	 * We can modify the key element of the node without destroying
	 * the minheap property, because we change every element.
	 */
	pev = base->timeheap.p;
	size = base->timeheap.n;
	for (; size-- > 0; ++pev) {  //将时间堆中的时间减去上面计算出的时间差
		struct timeval *ev_tv = &(**pev).ev_timeout;
		evutil_timersub(ev_tv, &off, ev_tv);
	}
	for (i=0; i<base->n_common_timeouts; ++i) {//将超时事件队列中的时间也调整,送去时间差
		struct event *ev;
		struct common_timeout_list *ctl =
		    base->common_timeout_queues[i];
		TAILQ_FOREACH(ev, &ctl->events,
		    ev_timeout_pos.ev_next_with_common_timeout) {
			struct timeval *ev_tv = &ev->ev_timeout;
			ev_tv->tv_usec &= MICROSECONDS_MASK;
			evutil_timersub(ev_tv, &off, ev_tv);
			ev_tv->tv_usec |= COMMON_TIMEOUT_MAGIC |
			    (i<<COMMON_TIMEOUT_IDX_SHIFT);
		}
	}

	/* Now remember what the new time turned out to be. */
	base->event_tv = *tv;
}
参考: http://blog.csdn.net/sparkliang/article/category/660506













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kgduu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值