libevent 源码学习六 —— 事件处理框架 event_base
前言 :Reactor 模型的框架组件 event_base 结构体, 位于 event-internal.h 文件中
1. 结构体定义与解释
struct event_base {
const struct eventop *evsel;
void *evbase;
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;
int nactivequeues;
/* signal handling info */
struct evsignal_info sig;
struct event_list eventqueue;
struct timeval event_tv;
struct min_heap timeheap;
struct timeval tv_cache;
};
evsel 和 evbase :evsel 通过 ev_base 来实际执行操作。ev_sel 指向全局变量 eventops[] 中的一个。 eventop 封装系统提供的 I/O 多路复用机制。
eventop 结构体的成员是一系列的函数指针,在event-internal.h 中
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;
};
在 libevent 中 ,每种 I/O demultiplex 机制的实现都要提供这5个函数接口,完成自身的初始化、销毁释放、对事件的注册、注销、和分发。
activequeues 是一个二级指针, libevent 支持事件的优先级,activequeues[priority] 是一个链表,每个节点指向一个优先级为 priorrity 的就绪事件 event。
eventqueue 链表。保存了所有的注册事件 event 的指针
sig 管理信号的结构体
timeheap 管理定时事件的小根堆
event_tv 和 tv_cache 是 libevent 用于时间管理的变量
2 创建和初始化 event_base
程序通过调用 event_init 函数来创建和初始化。
3 接口函数
libevent中对应的接口函数主要就是
int event_add(struct event *ev, const struct timeval *timeout);
int event_del(struct event *ev);
int event_base_loop(struct event_base *base, int loops);
void event_active(struct event *event, int res, short events);
void event_process_active(struct event_base *base);
a 注册事件
int event_add (struct event *ev, const struct timeval *tv) ev : 要注册的事件 tv : 超时时间
函数将 ev 注册到 ev->ev_base 上, 事件类型由 ev->ev_base 指明,如果注册成功,ev 将被插入到已注册链表中;如果 rv 不为 NULL,则会同时注册定时事件,将 ev 添加到 timer堆上。如果有一步操作失败,函数保证没有事件会被注册。
int event_add(struct event *ev, const struct timeval *tv){
struct event_base *base = ev->ev_base; // 要注册到的 event_base
const struct eventop *evsel = base -> evsel;
void * evbase = base -> evbase; // 系统采用的 I/O 策略
/*
** 新的 timer 事件,调用 timer heap 接口在堆上预留一个位置
** 保证操作的原子性
** 向系统 I/O 注册可能会失败,而当在堆上预留成功后,定时事件的添加肯定不会失败
** 预留位置的可能结果是堆扩充,内部元素并不会改变
*/
if(tv != NULL && !(ev -> ev_flags & EVLIST_TIMEOUT))
{
if(min_heap_reserve(&base -> timeheap, 1 + min_heap_size(&base -> timeheap)) == -1)
return -1 ;
}
// 如果事件 ev 不在已注册或激活链表中,测调用 evbase 注册事件。
if((ev -> ev_events & (EV_READ|EV_WRITE|EVSIGNAL)) && !(ev -> ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE)))
{
res = evsel -> add(evbase, ev);
if(res != -1) // 注册成功, 插入 event 到已注册链表中
event_queue_insert(base, ev, EVLIST_INSERTED);
}
// 准备添加定时事件
if(res != -1 && ev != NULL)
{
struct timeval now;
// EVLIST_TIMEOUT 表明 event 已经在定时器堆中了,删除旧的
if(ev -> ev_flags & EVLSIT_TIMEOUT)
event_queue_remove(base, ev, EVLIST_TIMEOUT);
// 如果事件已经是就绪状态,则从激活链表中删除
if((ev -> ev_flags & EVLIST_ACTIVE) && (ev -> ev_res & EV_TIMEOUT))
{
if(ev -> ev_ncalls && ev -> ev_pnacalls)
*ev -> ev_pncalls = 0;
event_queue_remove(base, ev, EVLIST_ACTIVE);
}
// 计算时间,并插入到 timer 小根堆中
gettime(base, &now);
evutil_timeradd(&now, tv, &ev -> ev_timeout);
event_queue_insert(base, ev, EVLIST_TIMEOUT);
}
return res;
}
event_queue_insert() 负责将事件插入到对应的链表中。
void event_queue_insert(struct event_base *base, struct event *ev, int queue){
if(ev -> ev_flags & queue)
if(queue & EVLIST_ACTIVE)
return;
ev -> ev_flags |= queue;
swith(queue)
{
case EVLIST_INSERT:
TAILQ_INSERT_TAIL(&base -> eventqueue, ev, ev_next);
break;
case EVLIST_ACTIVE:
base -> event_count_active++;
TAILQ_INSERT_TAIL(base -> activequeues[ev -> ev_pri], ev, ev_active_next);
break;
case EVLIST_TIMEOUT:
min_heap_push(&base -> timeheap, ev);
break;
}
}
b 删除事件
int event_del (struct event *ev); // 删除事件的操作不一定是原子的
int event_del(struct event *ev){
struct event_base *base;
const struct eventop *evsel;
void *evbase;
// 如果 ev_base 为 NULL, 表明 ev 没有被注册
if(ev -> ev_base == NULL)
return -1;
// 取得 ev 注册的 event_base 和 eventop 指针
base = ev -> ev_base;
evsel = base -> evsel;
evbase = base -> evbase;
// 将 ev_callback 调用次数设置为 0
if(ev -> ev_nacalls && ev -> ev_pncalls)
* ev -> ev_pncalls = 0;
// 从对应的链表中删除
if(ev -> ev_flags & EVLIST_TIMEOUT)
event_queue_remove(base, ev, EVLIST_TIMEOUT);
if(ev -> ev_flags & EVLIST_ACTIVE)
event_queue_remove(base, ev, EVLIST_ACTIVE);
if(ev -> ev_flags & EVLIST_INSERT)
{
event_queue_remove(base, ev, EVLIST_INSERT);
return (evsel -> del(evbase, ev));
}
return 0;
}