读书人

libevent0.1amp;0.2源码懂得(二)主要函

发布时间: 2012-09-22 21:54:54 作者: rapoo

libevent0.1&0.2源码理解(二)主要函数
修改记录:
3-29 初稿

介绍完类型与变量之后,就可以开始看程序的主轴了。我们从使用event-test.c入手可以看到的是:(略去之前创建命名管道和socket)

//这个是0.2版本的处理循环      while (1) {timeout_next(&tv);event_inloop = 1;res = evsel->dispatch(evbase, &tv);event_inloop = 0;if (res == -1)return (-1);maxfd = 0;for (ev = TAILQ_FIRST(&addqueue); ev;      ev = TAILQ_FIRST(&addqueue)) {TAILQ_REMOVE(&addqueue, ev, ev_add_next);ev->ev_flags &= ~EVLIST_ADD;event_add_post(ev);if (ev->ev_fd > maxfd)maxfd = ev->ev_fd;}if (evsel->recalc(evbase, maxfd) == -1)return (-1);timeout_process();}


dispatch是重中之重,里面进行的操作如下
重新计算fd_set也就是readset或者sop->event_readset变量所需要的空间大小,并把fd_set清零。把readqueue与writequeue中的所有事件的套接字放入fd_set中。从timequeue队列中取出第一个定时器到时时间tv。在tv时间之前select读写的fd_set锁上循环区(event_inloop=1),一一取readqueue或eventqueue的事件,先把这些事件从所有队列中移除之后,在一一调用各事件的回调函数即fifo_read。传入fifo_read的参数包括该事件的指针。fifo_read中再次调用event_set把event加入队列中,下次循环便会继续监听此事件。解锁循环区(event_inloop=0),把addqueue中的event全部取出来,放进readqueue或者0.2版本中的eventqueue调用recalc重新计算fd_set,也就是2中的步骤最后,对照当前时间,把timequeue队列中还没有超时的事件取出来调用回调函数。
注:0.1和0.2版本的处理顺序有所不同(在进入循环区前后所调用的东西不同。0.1是select之后再循环,0.2反之),但基本上一致

至此除event_pending外的主要函数全部介绍完毕(event_pending主要用来检查某个事件是否已被标记在计划中)

总结:
libevent0.x主要使用了Tail Queue这一数据结构存放系统各种待处理的事件队列。(现在觉得这种类型蛮奇葩的,用双向链表应该也是可以,不知Niels当初有何考量)其中一个事件(event)包含了对应的套接字和当时队列中下一个事件的指针。
每次在回调之后,都需要重新把事件加入到队列中,这是因为每次select的对象都是队列。
在0.1的一个循环中,程序先处理readqueue再处理writequeue。在0.2中,libevent把read和write一视同仁,都合并成了eventqueue

读书人网 >编程

热点推荐