libevent事件处理的中心部分——事件主循环,根据系统提供的事件多路分发机制执行事件循环,对已注册的就绪事件,调用注册事件的回调函数来处理事件。
事件处理主循环
libevent的事件主循环主要是通过event_base_loop ()函数完成的,其主要操作如下面的流程图所示,event_base_loop所作的就是持续执行下面的循环。
上图的简单描述就是:
- 校正系统当前时间。
- 将当前时间与存放时间的最小堆中的时间依次进行比较,将所有时间小于当前时间的定时器事件从堆中取出来加入到活动事件队列中。
- 调用I/O封装(比如:Epoll)的事件分发函数dispatch函数,以当前时间与时间堆中的最小值之间的差值(最小堆取最小值复杂度为O(1))作为Epoll/epoll_wait(Epoll.c/dispatch/407)的timeout值,在其中将触发的I/O和信号事件加入到活动事件队列中。
- 调用函数event_process_active(Event.c/1406)遍历活动事件队列,依次调用注册的回调函数处理相应事件。
int event_base_loop(struct event_base *base, int flags)
{
const struct eventop *evsel = base->evsel;
void *evbase = base->evbase;
struct timeval tv;
struct timeval *tv_p;
int res, done;
// 清空时间缓存
base->tv_cache.tv_sec = 0;
// evsignal_base是全局变量,在处理signal时,用于指名signal所属的event_base实例
if (base->sig.ev_signal_added)
evsignal_base = base;
done = 0;
while (!done) { // 事件主循环
// 查看是否需要跳出循环,程序可以调用event_loopexit_cb()设置event_gotterm标记
// 调用event_base_loopbreak()设置event_break标记
if (base->event_gotterm) {
base->event_gotterm = 0;
break;
}
if (base->event_break) {
base->event_break = 0;
break;
}
// 校正系统时间,如果系统使用的是非MONOTONIC时间,用户可能会向后调整了系统时间
// 在timeout_correct函数里,比较last wait time和当前时间,如果当前时间< last wait time
// 表明时间有问题,这是需要更新timer_heap中所有定时事件的超时时间。
timeout_correct(base, &tv);
// 根据timer heap中事件的最小超时时间,计算系统I/O demultiplexer的最大等待时间
tv_p = &tv;
if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
timeout_next(base, &tv_p);
} else {
// 依然有未处理的就绪时间,就让I/O demultiplexer立即返回,不必等待
// 下面会提到,在libevent中,低优先级的就绪事件可能不能立即被处理
evutil_timerclear(&tv);
}
//