// include/event2/event_struct.h
struct event {
TAILQ_ENTRY(event) ev_active_next; // 已就绪的事件链表
TAILQ_ENTRY(event) ev_next; // 已注册的事件链表
/* for managing timeouts */
union {
TAILQ_ENTRY(event) ev_next_with_common_timeout;
int min_heap_idx; // 事件在堆对应的数组下标
} ev_timeout_pos;
evutil_socket_t ev_fd; //对于I/O事件,是绑定的文件描述符;对于signal事件,是绑定的信号
struct event_base *ev_base; //指向事件框架实例
union {
/* used for io events */
struct {
TAILQ_ENTRY(event) ev_io_next;
struct timeval ev_timeout;
} ev_io;
/* used by signal events */
struct {
TAILQ_ENTRY(event) ev_signal_next;
short ev_ncalls; //事件就绪执行时,调用ev_callback的次数
/* Allows deletes in callback */
short *ev_pncalls; //指针,通常指向 ev_ncalls 或者为 NULL
} ev_signal;
} _ev;
short ev_events; //event的事件类型
short ev_res; //事件的回调函数的执行结果
short ev_flags; //用于标记 event信息的字段,表明事件当前的状态
ev_uint8_t ev_pri; //事件的优先级设置,值越小,则优先级越高
ev_uint8_t ev_closure; //
struct timeval ev_timeout; //超时设置
/* allows us to adopt for different types of events */
void (*ev_callback)(evutil_socket_t, short, void *arg);
void *ev_arg;
};
其中主要字段说明如下:
1 . ev_next,ev_active_next 和 ev_signal_next 都是双向链表节点指针;通过双向链表对不同类型、不同状态的事件进行管理。libevent 使用双向链表保存所有注册的 I/O和 Signal 事件,ev_next 指向“已注册事件链表”,其包含了所有的已注册的事件; ev_io_next 指向I/O事件在I/O事件链表中的位置; ev_signal_next 就是 signal 事件在 signal 事件链表中的位置; ev_active_next指向已激活的事件在active链表中的位置。
2 . ev_events
即event注册的事件类型
#define EV_TIMEOUT 0x01 // 定时事件
#define EV_READ 0x02 // IO事件读
#define EV_WRITE 0x04 // IO事件写
#define EV_SIGNAL 0x08 // 信号事件
#define EV_PERSIST 0x10 // 表明是一个永久事件
3 . ev_flags
某个event可在多个队列中,通过标志来标记event的当前所在的位置,状态值:
#define EVLIST_TIMEOUT 0x01 //event在min_heap中
#define EVLIST_INSERTED 0x02 //event在已注册的事件链表中
#define EVLIST_SIGNAL 0x04 //event在event_signal_map中
#define EVLIST_ACTIVE 0x08 //event在激活的链表中
#define EVLIST_INTERNAL 0x10 //内部使用标记
#define EVLIST_INIT 0x80 //event已经初始化
注:event_io_map 容器没有专门标志, 如果 ev_event 有 EV_READ|EV_WRITE, event_add 后一定在 event_io_map 中。且EV_READ|EV_WRITE不能和signal同时出现。
4 . 其他
min_heap
基于小根堆管理超时event,其中min_heap[0] 存放在第一个(最快)要超时的 event (的指针).
event_io_map
一个 hashtable, key是fd, value是fd对应的事件list. 如果对一个fd监控可读或可写时间的话, 那么这个fd绑定的 event 就会被加入到 value 的list 中. 同理如果 event_del 一个监控可读|可写事件的event, 那么也会从 key(fd)->value->list 中删除对应事件.
event_signal_map
与event_io_map 相似,也可以认为是一个 hashtable, key 是 signal number(signo), value 是这个 signo 对应的 event list.(一个信号可以对应多个event, 信号发生后会挨个调用这些event 的回调).