event不能单独的存在,而是被event_base结构组织在一起。在event_base中,struct event_list **activequenes用于组织不同优先级的活动事件,struct min_heap timeheap用于组织所有TIMEOUT事件,struct evsignal_info sig用于组织所有的SIGNAL事件。而struct event_list eventquene用于组织所有被插入的事件(包括IO,SIGNAL,不包含TIMEOUT)。
调用event_add添加事件时,如果是TIMEOUT事件,则添加到最小堆中;否则(IO,SIGNAL)先调用对应实现相关的add函数进行注册,然后调用event_queue_insert,将事件添加到eventquene中。
event_queue_insert函数根据插入类型quene选择不同的链表进行插入。
代码如下:
int event_add(struct event *ev, const struct timeval *tv)
{
if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
if (min_heap_reserve(&base->timeheap,
1 + min_heap_size(&base->timeheap)) == -1)
return (-1); /* ENOMEM == errno */
}
if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
res = evsel->add(evbase, ev); /*调用select_add或者 epoll_add,他们根据事件是否为signal决定是否调用evsignal_add*/
if (res != -1)
event_queue_insert(base, ev, EVLIST_INSERTED); /* 插入到事件列表 */
}
{
if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
if (min_heap_reserve(&base->timeheap,
1 + min_heap_size(&base->timeheap)) == -1)
return (-1); /* ENOMEM == errno */
}
if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
res = evsel->add(evbase, ev); /*调用select_add或者 epoll_add,他们根据事件是否为signal决定是否调用evsignal_add*/
if (res != -1)
event_queue_insert(base, ev, EVLIST_INSERTED); /* 插入到事件列表 */
}
}
支持Libevent运转的就是一个大循环,这个主循环体现在event_base_loop(Event.c/1533)函数里,该函数的执行流程如下:

图1 event_base_loop主循环
(1)校正系统当前时间。
(2)将当前时间与存放时间的最小堆中的时间依次进行比较,将所有时间小于当前时间的定时器事件从堆中取出来加入到活动事件队列中。
(3)调用I/O封装(比如:Epoll)的事件分发函数dispatch函数,以当前时间与时间堆中的最小值之间的差值(最小堆取最小值复杂度为O(1))作为Epoll/epoll_wait(Epoll.c/dispatch/407)的timeout值,在其中将触发的I/O和信号事件加入到活动事件队列中。
(4)调用函数event_process_active(Event.c/1406)遍历活动事件队列,依次调用注册的回调函数处理相应事件。