关于时间操作的一些函数:
- int event_add(struct event *ev,const struct timeval *tv)
-
{
-
int res;
-
-
if(EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
-
event_warnx(“%s:event has no event_base set.”,__func__);
-
return -1;
-
}
-
-
EVBASE_ACQUIRE_LOCK(ev->ev_base,th_base_lock);
-
res = event_add_internal(ev,tv,0);//将定时器放入事件队列中
-
EVBASE_RElEASE_LOCK(ev->ev_base,th_base_lock);
-
return (res);
-
}
-
-
static inline int event_add_internal(struct event *ev,const struct timeval *tv,int tv_is_absolute)
-
{
-
…..
-
if(res != -1 && tv != NULL) {
-
struct timeval now;
-
int common_timeout;
-
-
//如果定时器是连续行为,则记住超时时间
-
if(ev->ev_closure == EV_CLOSEURE_PERSIST && !tv_is_absolute)
-
ev->ev_io_timeout = *tv;
-
-
if(ev->ev_flags & EVLIST_TIMEOUT) {
-
//堆的最小时间索引是否为0
-
if(min_heap_elt_is_top(ev)) notify = 1;
-
//从定时链表中删除
-
event_queue_remove(base,ev,EVLIST_TIMEOUT);
-
}
-
-
if((ev->ev_flags & EVLIST_ACTIVE) && (ev->ev_res & EV_TIMEOUT)) {
-
if(ev->ev_event & EV_SIGNAL) {
-
if(ev->ev_ncalls && ev->ev_pncalls) {
-
*ev->ev_pncalls = 0;
-
}
-
}
-
evevnt_queue_remove(base,ev,EVLIST_ACTIVE);
-
}
-
gettime(base,&now);
-
common_timeout = is_common_timeout(tv,base);
-
if(tv_is_absolute) {
-
ev->ev_timeout = *tv;
-
} else if(common_timeout) {
-
struct timeval tmp = *tv;
-
tmp.tv_usec &= MICROSECONDS_MASK;
-
//#define evutil_timeradd(tvp,uvp,vvp) timeradd((tvp),(uvp),(vvp))
-
//形成绝对时间
-
evutil_timeradd(&now,&tmp,&ev->ev_timeout);
-
ev->ev_timeout.tv_usec |= (tv->tv_usec & ~MICROSECONDS_MASK);
-
} else {
-
evutil_timeradd(&now,tv,&ev->ev_timeout);
-
}
-
….......
-
//加入到堆中,比较绝对时间来进行调整堆
-
event_queue_insert(base,ev,EVLIST_TIMEOUT);
-
if(common_timeout) {
-
struct common_timeout_list *ctl = get_common_timeout_list(base,
-
&ev-> ev_timeout);
-
if(ev == TAILQ_FIRST(&ctl->events)) {
-
common_timeout_schedule(ctl,&now,ev);
-
}
-
} else {
-
if(min_heap_elt_is_top(ev)) notify = 1;
-
}
-
}
-
-
if( res != -1 && notify && EVBASE_NEED_NOTIFY(base))
-
evthread_notify_base(base);
-
_event_debug_note_add(ev);
-
-
return (res);
-
}
在事件循环函数中,epoll_wait之后,进行判断是否超时:
- int event_base_loop(struct event_base *base,int flags)
-
{
-
…..
-
if(!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK))
-
{
-
timeout_next(base,&tv_p);//从堆顶取出一个最小时间,作为epoll_wait中的timeout值
-
}
-
…..
-
res = evsel->dispatch(base,tv_p);
-
…..
-
timeout_process(base);//处理超时事件,将其插入活跃链表中
-
…....
-
if(N_ACTIVE_CALLBACKS(base)) {
-
/*处理活跃链表,该函数通过调用event_process_active_single_queue
-
-->event_persist_closure
-
-->event_add_internal又将该定时器加入到堆中*/
-
int n = event_process_active(base);
-
if((flags & EVLOOP_ONCE)
-
&& N_ACTIVE_CALLBACKS(base) == 0
-
&& n != 0)
-
done = 1;
-
}else if(flag & EVLOOP_NONBLOCK)
-
done = 1;
-
…..
-
}
-
-
static void timeout_process(struct event_base *base)
-
{
-
struct timeval now;
-
struct event *ev;
-
-
if(min_heap_empty(&base->timeheap))
-
{ return; }
-
-
gettime(base,&now);
-
-
while((ev = min_heap_top(&base->timeheap)))
-
{
-
//如果ev->ev_timeout > now,最大的时间都没有到则退出
-
if(evutil_timercmp(&ev->ev_timeout,&now,>))
-
break;
-
-
/*delete this event from the I/O queues**/
-
event_del_internal(ev);
-
event_debug(“timeout process: call %p”,ev->ev_callback));
-
//插入进入活跃链表
-
event_active_nolock(ev,EV_TIMEOUT,1);
-
}
-
-
}
-
-
void event_active_nolock(struct event *ev,int res,short ncalls)
-
{
-
struct event_base *base;
-
-
event_debug((“event_cache:%p (fd %d),res %d,callback %p”,ev,(int)ev->ev_fd,(int)res,ev->ev_callback));
-
-
if(ev->ev_flags & EVLIST_ACTIVE)
-
{
-
ev->ev_res |= res;
-
return;
-
}
-
-
base = ev->base;
-
EVENT_BASE_ASSERT_LOCKED(base);
-
ev->ev_res = res;
-
if(ev->ev_events & EV_SIGNAL) {
-
#ifndef _EVENT_DISABLE_THRED_SUPPORT
-
if(base->current_event) == ev && !EVBASE_IN_THREAD(base) {
-
++base->current_event_waiters;
-
EVTHREAD_COND_WAIT(base->current_event_cond,base->th_base_lock);
-
}
-
#endif
-
ev->ev_calls = ncalls;
-
ev->ev_pncalls = NULL;
-
}
-
//放入活跃链表
-
event_queue_insert(base,ev,EVLIST_ACTIVE);
-
-
if(EVBASE_NEED_NOTIFY(base))
-
evthread_notify_base(base);
-
}
上面的定时器流程大概可以表述如下:
while(1){
从小顶堆中取出堆顶元素,计算出相对时间
将此时间作为epoll_wait参数
epoll_wait返回后,处理到时事件
如果有超时则放入活跃链表中,并从堆中删除
判断活跃链表类型,如果超时为永久事件,则又重新放入到堆中
}
参考资料:
http://www.cppblog.com/converse/archive/2009/01/03/71040.aspx
http://blog.dccmx.com/2011/05/timer-implementation/
阅读(1410) | 评论(0) | 转发(0) |