libevent 源码学习九 —— 集成定时器事件
前言 : 与 Signal 相比,Timer 事件的集成会直观和简单很多
1. 集成到事件主循环
因为系统的 I/O 机制都允许程序制定一个最大的等待时间 timeout。就可以根据 Timer 事件的最小超时时间来设置系统 I/O 的 timeout时间。
2 代码解析
if(!base -> event_count_active && !(flags & EVLOOP_NONBLOCK))
{// 根据 TImer 事件计算 evsel -> dispatch 的最大等待时间
timeout_next(base, &tv_p);
}
else
{// 如果还有活动事件,就不要等待,让 evsel -> dispatch 立即返回
evutil_timerclear(&tv);
}
res = evsel -> dispatch(base, evbase, tv_p);
// 处理超时事件,插入到激活链表中
timeout_process(base)
timeout_next() 函数根据堆中具有最小超时值的事件和当前时间来计算等待时间。
static int timeout_next(struct event_base *base, struct timeval ** tv_p){
struct timeval now;
struct event *event;
struct timeval *tv = *tv_p;
// 堆的首元素具有最小的超时值
if((ev = min_heap_top(&base -> timeheap)) == NULL )
{// 如果没有定时事件, 将等待时间设置为 NULL
*tv_p = NULl;
return 0;
}
// 取得当前时间
gettime(base, &now);
// 如果超时时间 <= 当前值,不能等待,需要立即返回
if(evutil_timercmp(&ev -> ev_timeout, &now, <=))
{
evutil_timerclear(tv);
return 0;
}
// 计算等待的时间 = 当前的时间 - 最小的超时时间
evutil_timersub(&ev -> ev_timeout, &now, tv);
return 0;
}