卓航论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 293|回复: 2
打印 上一主题 下一主题

libevent源码浅析(四)

[复制链接]
[至尊红钻5级]发帖数量≥8000篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [至尊紫钻4级]金币≥20000个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 论坛元老
 UID:  7   [未点亮普号显示]钻石不足3个
 阁 分: 36567
 阁 望: 0
 阁 献: 0
 活 跃: 0
 发 贴: 12405 (0)
 阁 币: 24162  
性 别: I'm 火星人!
阅读权限: 90
在线时长: 0 小时
注册时间: 2016-10-16
最后登录: 2016-10-18
go
楼主
发表于 2016-10-17 16:27:11 |只看该作者 |倒序浏览
本帖发表于 2016-10-17 16:27:11...阅读 294 人...加油,亲爱的楼主:[db:作者]
最近刚刚一个项目自己用libevent,因此这几天又把libevent的代码拿出来翻了下,当初看的时候有些似是而非的东西,这次是基本没有了。这篇也算是前面几篇libevent的blog的补充了。
struct event_base {
 const struct eventop *evsel;
 void *evbase;
 int event_count; /* counts number of total events */
 int event_count_active; /* counts number of active events */
 int event_gotterm; /* Set to terminate loop */
 int event_break; /* Set to terminate loop immediately */
 /* active event management */
 struct event_list **activequeues;
 int nactivequeues;
 /* signal handling info */
 struct evsignal_info sig;
 struct event_list eventqueue;
 struct timeval event_tv;
 struct min_heap timeheap;
 struct timeval tv_cache;
};
我们这里用select来讲,其他的事件驱动器都相似。
我们来看,其中activequeues我们知道是表示激活的事件队列.这里libevent的处理是,select被唤醒后,调用 event_active方法,将此事件插入到activequeues队列中,这里这个队列的实现是用tail queue。然后libevent会执行event_process_active方法,从而从激活队列中,依次执行所激活的事件。这里这个队列之所以是一个指针的指针,是因为,libevent中事件还分为优先级,这样每个优先级都有一个activequeues队列。
记下来我们再来看定时器的实现,libevent会在每次执行循环时,从优先级队列中取出来最小的那个时间,然后将它加入到select中,从而实现定时器。而在每次select超时退出后,libevent会从小到大取出超时时间(直到大于当前时间),每次和当前时间比较,如果已超时,则会从优先级队列中删除此节点,然后将此超时事件加入到激活队列中。
接下来我们来看相关代码。
int
event_base_loop(struct event_base *base, int flags)
{
..................................................
 timeout_correct(base, &tv);
 tv_p = &tv;
///判断是否有激活事件,如果没有的话我们则会从优先级队列中取出最小的那个时间。也就是离现在最近的那个超时时间。
 if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
///下面会介绍这个函数
  timeout_next(base, &tv_p);
 } else {
  /*
  * if we have active events, we just poll new events
  * without waiting.
  */
  evutil_timerclear(&tv);
 }
.........................................................
 /* clear time cache */
 base->tv_cache.tv_sec = 0;
///调用相关事件驱动引擎的dispatch方法,这个方法中会将已激活的事件加入到激活队列,这里看到tv_p也就是上面取到的超时时间被传入到dispatch。
 res = evsel->dispatch(base, evbase, tv_p);
 if (res == -1)
  return (-1);
 gettime(base, &base->tv_cache);
///处理超时事件,将所有已超时的事件加入到激活队列。下面我们会介绍这个函数
 timeout_process(base);
 if (base->event_count_active) {
 ///执行激活事件队列
  event_process_active(base);
  if (!base->event_count_active && (flags & EVLOOP_ONCE))
///判断是否退出。
  done = 1;
 } else if (flags & EVLOOP_NONBLOCK)
  done = 1;
 }
 /* clear time cache */
 base->tv_cache.tv_sec = 0;
 event_debug(("%s: asked to terminate loop.", __func__));
 return (0);
}
               
来看timeout_next方法
static int
timeout_next(struct event_base *base, struct timeval **tv_p)
{
 struct timeval now;
 struct event *ev;
 struct timeval *tv = *tv_p;
///取出最小的那个时间。
 if ((ev = min_heap_top(&base->timeheap)) == NULL) {
 /* if no time-based events are active wait for I/O */
 *tv_p = NULL;
 return (0);
 }
///得到当前的时间。
 if (gettime(base, &now) == -1)
 return (-1);
///已超时则直接退出
 if (evutil_timercmp(&ev->ev_timeout, &now, ev_timeout, &now, tv);
 assert(tv->tv_sec >= 0);
 assert(tv->tv_usec >= 0);
 event_debug(("timeout_next: in %ld seconds", tv->tv_sec));
 return (0);
}
void
timeout_process(struct event_base *base)
{
..............................................
 gettime(base, &now);
///开始遍历此优先级队列
 while ((ev = min_heap_top(&base->timeheap))) {
///如果比当前时间大,则说明还没到超时时间因此直接退出。
 if (evutil_timercmp(&ev->ev_timeout, &now, >))
  break;
///删除此超时事件,因此我们在使用定时器时,需要我们每次进入定时器后,再次add此事件。
 /* delete this event from the I/O queues */
 event_del(ev);
 event_debug(("timeout_process: call %p",
  ev->ev_callback));
///加入激活队列。
 event_active(ev, EV_TIMEOUT, 1);
 }
}
               
其中event_active是通过event_queue_insert来插入到激活队列的,因此我们来看这个函数:
void
event_queue_insert(struct event_base *base, struct event *ev, int queue)
{
..............................................
 ev->ev_flags |= queue;
 switch (queue) {
///这个主要用来保存所有的激活以及非激活队列,也就是eventqueue.
 case EVLIST_INSERTED: 
 TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
 break;
 case EVLIST_ACTIVE: 
///激活队列数加一,并将此事件插入到相应的优先级的激活队列中。
 base->event_count_active++;
 TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
   ev,ev_active_next);
 break;
 case EVLIST_TIMEOUT: {
///处理超时事件。
 min_heap_push(&base->timeheap, ev);
 break;
 }
 default: 
 event_errx(1, "%s: unknown queue %x", __func__, queue);
 }
}
最后来看执行激活队列
static void
event_process_active(struct event_base *base)
{
 struct event *ev;
 struct event_list *activeq = NULL;
 int i;
 short ncalls;
///取出相应的激活队列
 for (i = 0; i nactivequeues; ++i) {
 if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
  activeq = base->activequeues[i];
  break;
 }
 }
 assert(activeq != NULL);
///开始遍历上面取出的队列
 for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
 if (ev->ev_events & EV_PERSIST)
///如果有persist标志,则只从激活队列中移除此事件,否则则从全局事件列表中删除此事件。
  event_queue_remove(base, ev, EVLIST_ACTIVE);
 else
  event_del(ev);
 /* Allows deletes to work */
 ncalls = ev->ev_ncalls;
 ev->ev_pncalls = &ncalls;
///每个事件的回调函数的调用次数
 while (ncalls) {
  ncalls--;
  ev->ev_ncalls = ncalls;
///调用回调函数
  (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
  if (event_gotsig || base->event_break)
  return;
 }
 }
}
分享到: QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏0 支持支持0 反对反对0

使用道具 举报

[至尊红钻3级]发帖数量≥1000篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [未点亮至尊紫钻]金币不足100个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 金牌会员
 UID:  2   [未点亮普号显示]钻石不足3个
 阁 分: 1290
 阁 望: 0
 阁 献: 0
 活 跃: 0
 发 贴: 1285 (0)
 阁 币: 5  
性 别: I'm 火星人!
阅读权限: 70
在线时长: 0 小时
注册时间: 2016-10-14
最后登录: 2016-10-18
沙发
发表于 2016-10-18 13:31:41 |只看该作者
本回复帖发表于 2016-10-18 13:31:41,感谢hjghjgj对本帖的认真回复,你的回复是对楼主莫大的鼓舞
真是 收益 匪浅

使用道具 举报

[至尊红钻2级]发帖数量≥100篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [未点亮至尊紫钻]金币不足100个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 注册会员
 UID:  39   [未点亮普号显示]钻石不足3个
 阁 分: 145
 阁 望: 5
 阁 献: 5
 活 跃: 0
 发 贴: 120 (0)
 阁 币: 10  
性 别: I'm 火星人!
阅读权限: 20
在线时长: 2 小时
注册时间: 2011-1-6
最后登录: 2016-10-21
板凳
发表于 2016-10-20 10:01:14 |只看该作者
本回复帖发表于 2016-10-20 10:01:14,感谢deltero对本帖的认真回复,你的回复是对楼主莫大的鼓舞
找到好贴不容易,我顶你了,谢了

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1、请认真发帖,禁止回复纯表情,纯数字等无意义的内容!帖子内容不要太简单!
2、提倡文明上网,净化网络环境!抵制低俗不良违法有害信息。
3、每个贴内连续回复请勿多余3贴,每个版面回复请勿多余10贴!
4、如果你对主帖作者的帖子不屑一顾的话,请勿回帖。谢谢合作!

手机版| 百度搜索:vkee.pw

2012-2015 卓航旗下 GMT+8, 2024-6-16 19:02 , Processed in 8.228454 second(s), 31 queries . Powered by Discuz! X3.2  

禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.如遇版权问题,请及时联系站长(QQ:5213513)

今天是: | 本站已经安全运行: //这个地方可以改颜色

快速回复 返回顶部 返回列表