(虚线部分代表包含关系)
一、tail_queue
关于tail_queue的解释在上篇文章中很细致。
二、event
//event提供了函数接口,供Reactor在事件发生时调用,以执行相应的事件处理,
//通常它会绑定一个有效的句柄(ev_fd)做为回调函数的参数.
struct event {
//已注册事件队列入口
TAILQ_ENTRY (event) ev_next;
//已激活事件队列入口
TAILQ_ENTRY (event) ev_active_next;
//信号事件队列入口 不过在以前的分析中可以看到,将来这个队列中的内容会被添加到ev_active_next队列中。
TAILQ_ENTRY (event) ev_signal_next;
//表示该event在定时器事件最小堆min_heap的索引
unsigned int min_heap_idx; /* for managing timeouts */
//该事件所属的反应堆实例
struct event_base *ev_base;
//对于I/O事件,是绑定的文件描述符; 对于signal事件,是绑定的信号.
int ev_fd;
//表示事件类型: I/O,定时器或者信号
short ev_events;
//事件就绪执行时,将要调用ev_callback 的次数,通常为1
short ev_ncalls;
//该事件的超时时间,在定时器最小堆min_heap操作中作为节点值进行比较.
struct timeval ev_timeout;
//该事件的优先级,越小越优先.
int ev_pri; /* smaller numbers are higher priority */
//该事件被激活时的回调函数
void (*ev_callback)(int, short, void *arg);
//该事件的标记信息,表示其当前的状态,即它在哪个链表中
int ev_flags;
... //其他成员.
};
一个事件是可以插入到多个队列的,当它与一个反应堆实例(event_base)关联时,这个事件被插入到反应堆实例下的已注册事件队列 event_base -> eventqueue ,当它处于就绪状态时,会被插入到反应堆实例下的已激活事件队列 event_base -> activequeues[id], id = event -> ev_pri .同时,如果此事件是信号事件,那么它会被插入到反应堆结构体下的信号事件结构体下的信号队列 event_base -> evsignal_info -> evsigevents[id], id = event -> ev_fd .
需要指出的,每个事件都保持了一个成员 struct event_base *ev_base; ,它表示该事件属于哪个反应堆实例.
还有一个成员需要注意, short ev_events; ,它表明此事件的事件类型,libevent正是基于此实现对I/O,信号,定时 3种事件的封装的.
一般使用情况下,不申请struct event_base.因为在库中有一个全局的event_base,所有的事件都可以添加到这个全局event_base中!!!
三、min_heap
typedef struct min_heap
{
struct event** p; //p指向一个动态分配的数组,数组元素是event指针.
unsigned n, a; // n表示目前保存了多少元素,a表示p指向的内存能够存储event指针的个数.
} min_heap_t;
这个结构体的作用这里就不再累述
四、evsignal_info
这个结构体是用来管理信号事件的
struct evsignal_info {
//是否有信号发生的标记
volatile sig_atomic_t evsignal_caught;
//evsigevents[signo]表示注册到信号 signo 的事件链表
struct event_list evsigevents[NSIG];
//具体记录每个信号触发的次数,evsigcaught[signo]是记录信号signo被触发的次数
sig_atomic_t evsigcaught[NSIG];
... //其他成员
};
其中, struct event_list evsigevents[NSIG]; 成员是一个数组,它的元素 evsigevents[id] 表示注册到信号id的事件链表.
还有其他几个更加重要的结构体
event_base