Libevent 是基于事件驱动的,从名字也可以看到 event 是整个库的核心。event 就是 Reactor 框架中的事件处理程序组件;它提供了函数接口,供 Reactor 在事件发生时调用,以执行相应的事件处理,通常它会绑定一个有效的句柄。
1.event结构体:
/*事件类型宏定义*/
#define EV_TIMEOUT 0x01
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08
#define EV_PERSIST 0x10
struct event {
TAILQ_ENTRY (event) ev_next;
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;
int ev_fd;
short ev_events; //关注的事件类型
//i/o事件 EV_WRITE和EV_READ
//定时事件 EV_TIMEOUT
//信号事件 EV_SIGNAL
//永久事件 EV_PERSIST辅助选项
short ev_ncalls;
short *ev_pncalls; /* Allows deletes in callback */
struct timeval ev_timeout;
int ev_pri; /* smaller numbers are higher priority */
void (*ev_callback)(int, short, void *arg);
void *ev_arg;
int ev_res; /* result passed to event callback */
int ev_flags;
};
1) libevent使用event结构体将这3种事件的处理统一起来;
2)ev_next,ev_active_next 和 ev_signal_next 都是双向链表节点指针;它们是 libevent 对不同事件类型和在不同的时期,对事件的管理时使用到的字段。libevent 使用双向链表保存所有注册的 I/O 和 Signal 事件
- ev_next 就是该 I/O 事件在链表中的位置,称此链表为“已注册事件链表”;
- ev_signal_next 就是 signal 事件在 signal 事件链表中的位置;
- ev_active_next:libevent 将所有的激活事件放入到链表 active list 中,然后遍历 active list 执行调度,ev_active_next 就指明了 event 在 active list 中的位置;
3)min_heap_idx 和 ev_timeout,如果是 timeout 事件,它们是 event 在小根堆中的索引和超时值,libevent 使用小根堆来管理定时事件;
4)ev_base 该事件所属的反应堆实例,这是一个 event_base 结构体(事件处理框架);
5)ev_fd,对于 I/O 事件,是绑定的文件描述符;对于 signal 事件,是绑定的信号;
6)ev_callback,event 的回调函数,被 ev_base(反应堆实例) 调用,执行事件处理程序,这是一个函数指针,原型为:
void (*ev_callback)(int fd, short events, void *arg)
其中参数 fd 对应于 ev_fd; events 对应于 ev_events ; arg 对应于 ev_arg;
7)ev_arg:void*,表明可以是任意类型的数据,在设置 event 时指定;
8)eb_flags:libevent 用于标记 event 信息的字段,表明其当前的状态,可能的值有:
#define EVLIST_TIMEOUT 0x01 // event在time堆中
#define EVLIST_INSERTED 0x02 // event在已注册事件链表中
#define EVLIST_SIGNAL 0x04 // 未见使用
#define EVLIST_ACTIVE 0x08 // event在激活链表中
#define EVLIST_INTERNAL 0x10 // 内部使用标记
#define EVLIST_INIT 0x80 // event 已被初始化
2.对event的管理
1)每次当有事件 event 转变为就绪状态时,libevent就会把它移入到 active event list[priority]中,其中 priority 是 event 的优先级;接着 libevent 会根据自己的调度策略选择就绪事件,调用其 cb_callback()函数执行事件处理;并根据就绪的句柄和事件类型填充 cb_callback 函数的参数。
2)图示:
3. 事件设置的接口函数--------向libevent添加事件(设置event对象)
1)void event_set(struct event *ev, int fd, short events, void (*callback)(int, short, void *), void *arg)
- 设置事件 ev 绑定的文件描述符或者信号,对于定时事件,设为-1 即可;
- 设置事件类型,比如 EV_READ|EV_PERSIST, EV_WRITE, EV_SIGNAL 等;
- 设置事件的回调函数以及参数 arg;
2)设置 event ev 将要注册到的 event_base;
- int event_base_set(struct event_base *base, struct event *ev)
- libevent 有一个全局 event_base 指针 current_base,默认情况下事件 ev将被注册到 current_base 上,使用该函数可以指定不同的 event_base;
- 如果一个进程中存在多个 libevent 实例,则必须要调用该函数为 event 设置不同的 event_base;
3)设置event_ev的优先级,ev处于就绪状态不能设置优先级
int event_priority_set(struct event *ev, int pri)