前几次剖析了libevent的tail queue和evbuffer,今天来剖析一下它的事件处理框架。这个在剖析evbuffer之前已经大致走过几遍,但思路不是很清晰,是因为我没有用实例去测试event流程。通过这次我学习到了剖析源码不仅要去看源码,而且你要测试它这项接口是怎么用的,不然只会似懂非懂。
首先来看一下event结构体:
struct event {
TAILQ_ENTRY (event) ev_next; //已注册事件链表,名字叫ev_next,event是类型,非活跃, TAILQ_ENTRY在我之前的博客已经剖析过了,不再赘述
TAILQ_ENTRY (event) ev_active_next; //活跃事件链表,叫链表或者队列都行,下文碰见队列也是说这几个
TAILQ_ENTRY (event) ev_signal_next; //信号事件链表
unsigned int min_heap_idx; /* for managing timeouts */ //超时事件在小根堆中的索引
struct event_base *ev_base; //该事件所属的反应堆实例,它指向一个event_base反应堆
int ev_fd; //对于IO事件是文件描述符,对于信号事件,是绑定的信号
short ev_events; //关注的事件类型,如EV_WRITE,EV_READ,EV_TIMEOUT,EV_SIGNAL,EV_PRESIST,可以使用|组合
short ev_ncalls; //事件就绪时,调用ev_callback执行的次数,通常为1
short *ev_pncalls; /* Allows deletes in callback */ //通常指向event_ncalls,或者为NULL
struct timeval ev_timeout; //超时事件的超时值
int ev_pri; /* smaller numbers are higher priority */ //优先级
void (*ev_callback)(int, short, void *arg); //event回调函数,执行事件处理程序,fd对应ev_fd,events对应
//ev_events, arg对应ev_arg
void *ev_arg; //设置event时指定
int ev_res; /* result passed to event callback */ //记录了当前激活事件的类型
int ev_flags; //标记event信息的字段,表明当前状态,如EVLIST_TIMEOUT, EVLIST_INSERTED, EVLIST_ACTIVE等。
};
下面是event_base结构体:
struct event_base {
const struct eventop *evsel; //用来接收系统编译前设置I/O机制的名字,来自eventops
void *evbase; //接收init返回的I/O多路复用的op,如epollop
int event_count; /* counts number of total events */ //事件总数
int event_count_active; /* counts number of active events */ //活跃事件数目
int event_gotterm; /* Set to terminate loop */
int event_break; /* Set to terminate loop immediately */
/* active event management */
struct event_list **activequeues; //activequeues[priority]是一个链表,链表中的每个结点都是优先级为
//priority的就绪事件event
int nactivequeues; //活跃链表的数目
/* signal handling info */
struct evsignal_info sig; //专门管理信号的结构体
struct event_list eventqueue; //链表,保存了所有注册事件event的指针
struct timeval event_tv; //管理时间变量
struct min_heap timeheap; //用来管理定时时间的小根堆
struct timeval tv_cache; //管理时间变量
};
event_base中的evsel的类型是eventop类型,它的结构体是这样的:
struct eventop {
const char *name;
void *(*init)(struct event_base *); //初始化
int (*add)(void *, struct event *); //注册事件
int (*del)(void *, struct event *); //删除事件
int (*dispatch)(struct event_base *, void *, struct timeval *); //事件分发
void (*dealloc)(struct event_base *, void *); //注销,释放资源
/* set if we need to reinitialize the event base */
int need_reinit; //设置是否重新初始化
};
eventop即event operator,我们可以看到它的内部封装了事件操作的名字,以及各种方法,可以用来配合实现C语言的多态。这里实际上将会封装I/O多路复用选项,比如:name=epoll,然后init,add等方法就用epoll的方法,或者name=select,用select的方法。至于怎么选,看下面。
evsel实际上会在event_base_new函数里面初始化,会根据你在编译前的选项来选择I/O multiplexer,我把ecent_base_new函数中选择部分截取出来如下,以及eventops选项数组。
//根据系统配置和编译选项决定使用哪一种I/O demultiplex机制
//可以看出,libevent在编译阶段选择系统的I/O demultiplex机制,而不支持在运行阶段根据配置再次选择
base->evbase = NULL;
fo