// 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 . 其他
1 . 创建事件 (event_new)
主要完成event的空间分配,
struct event * event_new(struct event_base *base,
evutil_socket_t fd,
void (*cb)(evutil_socket_t, short, void *),
void *arg)
{
struct event *ev;
// 分配new event的空间
ev = mm_malloc(sizeof(struct event));
...
// event的参数赋值
ev->ev_base = base; // 依附的event_base
ev->ev_callback = callback; // 设置回调函数
ev->ev_arg = arg;
ev->ev_fd = fd;
ev->ev_events = events; // 该event注册的事件类型
ev->ev_res = 0;
ev->ev_flags = EVLIST_INIT; // ev_flags设置为初始化
ev->ev_ncalls = 0; // 回调函数执行了0次
ev->ev_pncalls = NULL;
// 根据event的ev_events的值,设置event的关闭方式
if (events & EV_SIGNAL) {...}
else
{
if (events & EV_PERSIST) { // event为
evutil_timerclear(&ev->ev_io_timeout); // 清除超时设置
ev->ev_closure = EV_CLOSURE_PERSIST;
} else {
ev->ev_closure = EV_CLOSURE_NONE;
}
}
...
// 优先级设置为active queue的大小的中间值
ev->ev_pri = base->nactivequeues / 2;
...
return (ev);
}
2 . 事件设置
对event的设置主要通过三个函数完成:event_set()、event_base_set()、event_priority_set()。
void event_set(struct event *ev,
int fd,
short events,
void (*callback)(int, short, void *), // event的回调函数
void *arg) // 用户传递的参数
int event_base_set(struct event_base *base, struct event *ev)
int event_priority_set(struct event *ev, int pri)
本文参考:
Libevent源码分析—–超时event的处理
libevent源码深度剖析