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;
}; 下面详细解释一下结构体中各字段的含义。struct eventop{
const char*name;
void*(*init)(struct event_base*); // 初始化
int(*add)(void*, struct event*); // 注册事件
int(*del)(void*, struct event*); // 删除事件
19
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机制的实现都必须提供这五个函数接口,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);
本节将按介绍事件注册和删除的代码流程,libevent 的事件循环框架将在下一节再具体
描述。
对于定时事件,这些函数将调用timer heap管理接口执行插入和删除操作;对于I/O和
20
Signal事件将调用eventopadd和delete接口函数执行插入和删除操作(eventop会对Signal
事件调用Signal处理接口执行操作);这些组件将在后面的内容描述。
1)注册事件
函数原型:
int event_add(struct event*ev, const struct timeval*tv)
参数:ev:指向要注册的事件;
tv:超时时间;
函数将ev注册到ev->ev_base上,事件类型由ev->ev_events指明,如果注册成功,ev
将被插入到已注册链表中;如果tv不是NULL,则会同时注册定时事件,将ev添加到timer
堆上;
如果其中有一步操作失败,那么函数保证没有事件会被注册,可以讲这相当于一个原子
操作。这个函数也体现了libevent细节之处的巧妙设计,且仔细看程序代码,部分有省略,
注释直接附在代码中。
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; // base使用的系统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); /* ENOMEM == errno */
}
// 如果事件ev不在已注册或者激活链表中,则调用evbase注册事件
if((ev->ev_events& (EV_READ|EV_WRITE|EV_SIGNAL)) &&
!(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 && tv!= NULL) {
struct timeval now;
// EVLIST_TIMEOUT表明event已经在定时器堆中了,删除旧的
if(ev->ev_flags& EVLIST_TIMEOUT)
event_queue_remove(base, ev, EVLIST_TIMEOUT);
21
// 如果事件已经是就绪状态则从激活链表中删除
if((ev->ev_flags& EVLIST_ACTIVE) &&
(ev->ev_res& EV_TIMEOUT)) {
// 将ev_callback调用次数设置为0
if(ev->ev_ncalls&& ev->ev_pncalls) {
*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()负责将事件插入到对应的链表中,下面是程序代码;
event_queue_remove()负责将事件从对应的链表中删除,这里就不再重复贴代码了;
void event_queue_insert(struct event_base*base, struct event*ev,
int queue)
{
// ev可能已经在激活列表中了,避免重复插入
if(ev->ev_flags& queue) {
if(queue& EVLIST_ACTIVE)
return;
}
// ...
ev->ev_flags|= queue; // 记录queue标记
switch(queue) {
case EVLIST_INSERTED: // I/O或Signal事件,加入已注册事件链表
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;
}
} 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调用次数设置为
if(ev->ev_ncalls&& 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_INSERTED) {
event_queue_remove(base, ev, EVLIST_INSERTED);
// EVLIST_INSERTED表明是I/O或者Signal事件,
// 需要调用I/O demultiplexer注销事件
return(evsel->del(evbase, ev));
}
return(0);
}原文:http://blog.csdn.net/yusiguyuan/article/details/18217231