libevent支持很多系统,因本人是做Linux后台的,故只看了epoll部分。
eventops 数组用来实现devpoll, kqueue, epoll, poll, select 实现的选择。
event_base * current_base; libevent 主要控制结构。
event_base 分3个队列 EVLIST_INSERTED, EVLIST_ACTIVE, EVLIST_TIMEROUT.
EVLIST_INSERTED 队列 保存 加入到event_base的所有event, 为什么要这个队列呢?
event.c中
/* reinitialized the event base after a fork */
int
event_reinit(struct event_base *base)
这个函数在fork 之后可以被调用,fork之后需要重新设置监听事件。
EVLIST_ACTIVE 分优先级的队列,不过默认是1个优先级(等于没有优先级)
EVLIST_TIMEROUT 是个数组,以超时组织的小端堆(删除,插入时间是lg(N))。
epoll.c
struct evepoll {
struct event *evread;
struct event *evwrite;
};struct epollop {
struct evepoll *fds;
int nfds;
struct epoll_event *events;
int nevents;
int epfd;
};
struct evepoll *fds; 有什么用?
struct evepoll {
struct event *evread;
struct event *evwrite;
}; 为什么要分读写?
原来libevent 支持一个fd 有两个 event对象的情形。
event r, w;
event_set(&r, fd, EV_READ,&r);
event_set(&w, fd, EV_WRITE,&r);
ev_read, ev_write 可以是不同的event, 也正因为fd可以有两个event, 所以不能放到 epoll_data_t中。(以前自己实现的时候就没有使用fd数组,因为所有的fd只有一个对用的控制结构)
struct evepoll *fds 是个数组,这带来极大的便利,通过fds[fd]就可以找到控制结构,这依赖于操作系统的特性(新fd总是系统中最小空闲fd.)
libevent 还可以延后处理signal, 通过一对unix套接字来唤醒epoll_wait,从而加速signal event的处理。
如果没有这样做的话,可能就要等到epoll_wait超时后才能调用,但epoll_wait的时间跟timer_out 队列的时间相关,
如果timer_out 队列为空,就更是糟糕。
总结:
libevent 也有个小缺陷,就是不支持多线程,不过一般不是大问题,因为长时间任务,都要自己实现线程组和队列。
linux 现在支持 timerfd 和siganlfd, 不过其它系统可能不支持。