Chinaunix首页 | 论坛 | 博客
  • 博客访问: 999553
  • 博文数量: 442
  • 博客积分: 1146
  • 博客等级: 少尉
  • 技术积分: 1604
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-04 12:52
个人简介

123

文章分类

全部博文(442)

文章存档

2017年(3)

2016年(15)

2015年(132)

2014年(52)

2013年(101)

2012年(110)

2011年(29)

分类: C/C++

2013-08-05 10:18:18

原文地址:libevent 中的定时器 作者:datao0907

关于时间操作的一些函数:

  1. int event_add(struct event *ev,const struct timeval *tv)
  2. {
  3.     int res;

  4.     if(EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
  5.         event_warnx(%s:event has no event_base     set.,__func__);
  6.         return -1;
  7.     }
  8.     
  9.     EVBASE_ACQUIRE_LOCK(ev->ev_base,th_base_lock);    
  10.     res = event_add_internal(ev,tv,0);//将定时器放入事件队列中
  11.     EVBASE_RElEASE_LOCK(ev->ev_base,th_base_lock);
  12.     return (res);
  13. }

  14. static inline int event_add_internal(struct event *ev,const struct timeval *tv,int tv_is_absolute)
  15. {
  16.     …..
  17.     if(res != -1 && tv != NULL) {
  18.         struct timeval now;
  19.         int common_timeout;
  20.     
  21.         //如果定时器是连续行为,则记住超时时间
  22.         if(ev->ev_closure == EV_CLOSEURE_PERSIST && !tv_is_absolute)
  23.             ev->ev_io_timeout = *tv;
  24.         
  25.         if(ev->ev_flags & EVLIST_TIMEOUT) {
  26.             //堆的最小时间索引是否为0
  27.             if(min_heap_elt_is_top(ev))    notify = 1;
  28.             //从定时链表中删除
  29.             event_queue_remove(base,ev,EVLIST_TIMEOUT);
  30.         }

  31.         if((ev->ev_flags & EVLIST_ACTIVE) && (ev->ev_res & EV_TIMEOUT)) {
  32.             if(ev->ev_event & EV_SIGNAL) {
  33.                 if(ev->ev_ncalls && ev->ev_pncalls) {
  34.                     *ev->ev_pncalls = 0;
  35.                 }
  36.             }
  37.             evevnt_queue_remove(base,ev,EVLIST_ACTIVE);
  38.         }
  39.         gettime(base,&now);
  40.         common_timeout = is_common_timeout(tv,base);
  41.         if(tv_is_absolute) {
  42.             ev->ev_timeout = *tv;
  43.         } else if(common_timeout) {
  44.             struct timeval tmp = *tv;
  45.             tmp.tv_usec &= MICROSECONDS_MASK;
  46.             //#define evutil_timeradd(tvp,uvp,vvp) timeradd((tvp),(uvp),(vvp))
  47.             //形成绝对时间
  48.             evutil_timeradd(&now,&tmp,&ev->ev_timeout);
  49.             ev->ev_timeout.tv_usec |= (tv->tv_usec & ~MICROSECONDS_MASK);
  50.         } else {
  51.             evutil_timeradd(&now,tv,&ev->ev_timeout);
  52.         }
  53.         ….......
  54.         //加入到堆中,比较绝对时间来进行调整堆
  55.         event_queue_insert(base,ev,EVLIST_TIMEOUT);
  56.         if(common_timeout) {
  57.             struct common_timeout_list *ctl = get_common_timeout_list(base,
  58.                 &ev->    ev_timeout);
  59.             if(ev == TAILQ_FIRST(&ctl->events)) {
  60.                 common_timeout_schedule(ctl,&now,ev);
  61.             }
  62.         } else {
  63.                 if(min_heap_elt_is_top(ev))        notify = 1;
  64.         }
  65.     }

  66.     if( res != -1 && notify && EVBASE_NEED_NOTIFY(base))
  67.         evthread_notify_base(base);
  68.     _event_debug_note_add(ev);

  69.     return (res);
  70. }

在事件循环函数中,epoll_wait之后,进行判断是否超时:

  1. int event_base_loop(struct event_base *base,int flags)
  2. {
  3.     …..
  4.     if(!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK))
  5.     {
  6.         timeout_next(base,&tv_p);//从堆顶取出一个最小时间,作为epoll_wait中的timeout值
  7.     }
  8.     …..
  9.     res = evsel->dispatch(base,tv_p);
  10.     …..
  11.     timeout_process(base);//处理超时事件,将其插入活跃链表中
  12.     …....
  13.     if(N_ACTIVE_CALLBACKS(base)) {
  14.         /*处理活跃链表,该函数通过调用event_process_active_single_queue
  15.                 -->event_persist_closure
  16.                     -->event_add_internal又将该定时器加入到堆中*/
  17.         int n = event_process_active(base);
  18.         if((flags & EVLOOP_ONCE)
  19.             && N_ACTIVE_CALLBACKS(base) == 0
  20.             && n != 0)
  21.                 done = 1;
  22.     }else if(flag & EVLOOP_NONBLOCK)
  23.         done = 1;
  24.     …..
  25. }

  26. static void timeout_process(struct event_base *base)
  27. {
  28.     struct timeval now;
  29.     struct event *ev;

  30.     if(min_heap_empty(&base->timeheap))
  31.     {    return;    }
  32.     
  33.     gettime(base,&now);
  34.     
  35.     while((ev = min_heap_top(&base->timeheap)))
  36.     {
  37.         //如果ev->ev_timeout > now,最大的时间都没有到则退出
  38.         if(evutil_timercmp(&ev->ev_timeout,&now,>))
  39.             break;
  40.         
  41.         /*delete this event from the I/O queues**/
  42.         event_del_internal(ev);
  43.         event_debug(“timeout process: call %p”,ev->ev_callback));
  44.         //插入进入活跃链表
  45.         event_active_nolock(ev,EV_TIMEOUT,1);
  46.     }

  47. }

  48. void event_active_nolock(struct event *ev,int res,short ncalls)
  49. {
  50.     struct event_base *base;
  51.     
  52.     event_debug((“event_cache:%p (fd %d),res %d,callback %p”,ev,(int)ev->ev_fd,(int)res,ev->ev_callback));
  53.     
  54.     if(ev->ev_flags & EVLIST_ACTIVE)
  55.     {
  56.         ev->ev_res |= res;
  57.         return;
  58.     }

  59.     base = ev->base;
  60.     EVENT_BASE_ASSERT_LOCKED(base);
  61.     ev->ev_res = res;
  62.     if(ev->ev_events & EV_SIGNAL) {
  63. #ifndef _EVENT_DISABLE_THRED_SUPPORT        
  64.         if(base->current_event) == ev && !EVBASE_IN_THREAD(base) {
  65.             ++base->current_event_waiters;
  66.             EVTHREAD_COND_WAIT(base->current_event_cond,base->th_base_lock);            
  67.         }    
  68. #endif        
  69.         ev->ev_calls = ncalls;
  70.         ev->ev_pncalls = NULL;
  71.     }
  72.     //放入活跃链表
  73.      event_queue_insert(base,ev,EVLIST_ACTIVE);
  74.     
  75.     if(EVBASE_NEED_NOTIFY(base))
  76.         evthread_notify_base(base);
  77. }

上面的定时器流程大概可以表述如下:

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/


阅读(1377) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~