libevent提供一种当特定事件发生、超时或信号到达时执行回调函数的机制,看了libevent的代码,里面包含了对普通事件、超时事件的处理;libevent-0.1(2000年发布)使用select来进行IO轮询,最新的libevent版本使用epoll。(http://monkey.org/~provos/libevent/)
libevent的实现框架(三个主体 — 事件、队列、处理):
l 事件,每个事件由一个struct event标示;
struct event {
// 事件所处队列的链接指针
TAILQ_ENTRY (event) ev_read_next;
TAILQ_ENTRY (event) ev_write_next;
TAILQ_ENTRY (event) ev_timeout_next;
TAILQ_ENTRY (event) ev_add_next;
int ev_fd; // 与事件关联的文件描述符
short ev_events; // 事件类型
struct timeval ev_timeout; // 事件超时时间
void (*ev_callback)(int, short, void *arg); // 时间达到时的回调函数
void *ev_arg; // 回调函数的参数
int ev_flags; // 事件所在的队列标志
};
l 队列
libevent定义了四种类型的队列(tail queue)
TAILQ_HEAD (timeout_list, event) timequeue; // 超时队列
TAILQ_HEAD (event_wlist, event) writequeue; // 写等待队列
TAILQ_HEAD (event_rlist, event) readqueue; // 读等待队列
TAILQ_HEAD (event_ilist, event) addqueue; // 添加队列
其中,超时队列中包含有超时时间限制的事件;添加队列中的时间为需要延时加入的事件(在调用event_add时,正在进行事件派遣event_dispatch,这些事件要等本轮派遣结束才能加入)。
libevent提供了event_set接口来构造事件;event_add接口来往相应的队列中添加事件(同一个fd上的多个事件只需要构造一个event,并指明事件类型,event_add会将事件添加到相应的队列中); event_del来从响应的队列删除事件。
l 处理(派遣)
libevent提供event_dispatch接口来派遣等待的事件。event_dispatch首先遍历各个等待队列,将时间对应的描述符和事件类型加入select的fdset,然后选择超时时间最近的的事件(超时队列中的事件在插入时是按超时时间排序的,新的libevent使用堆),根据差值设置select的超时时间。select返回后,再次遍历各个队列中的事件,如果事件(或超时时间)已到达,则执行回调函数。处理完后,将addqueue中的事件加入到相应的队列中去,然后执行下一轮派遣处理。