在之前我们分析了event
的注册和注销, 而本节就来分析event
又是如何被激活的.
event 激活
event_active 函数
// 将 event 事件主动设置到活动队列中
void
event_active(struct event *ev, int res, short ncalls)
{
/* We get different kinds of events, add them together */
// 如果事件已经在就绪队列中, 则更新返回事件的状态
if (ev->ev_flags & EVLIST_ACTIVE) {
ev->ev_res |= res;
return;
}
// 设置事件的状态并将事件添加到就绪队列中
ev->ev_res = res;
ev->ev_ncalls = ncalls; // 设置事件来临的总次数
ev->ev_pncalls = NULL;
event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
}
- 检查事件是否已经处于就绪队列中, 如果是则直接退出;
- 否则设置事件激活的类型以及事件被调用的次数
- 最后添加到就绪链表中
咋一看event_active
只是主动的将事件加入到就绪队列中啊, 并没被激活啊. 下面就来分析激活函数
event_process_active 激活函数
// 处理所有的优先级队列中的事件, 并对每一个事件调用回调函数
// 但是总是先处理低优先级, 高优先级可能会被饿死
static void
event_process_active(struct event_base *base)
{
struct event *ev;
struct event_list *activeq = NULL;
int i;
short ncalls;
// 从优先级低到高的顺序遍历, 如果低优先级队列不空, 则退出循环
for (i = 0; i < base->nactivequeues; ++i) {
if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
activeq = base->activequeues[i];
break;
}
}
assert(activeq != NULL);
// 从该优先级队列中开始进行调度
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
// 如果该事件设置是永久有效, 则只是将该事件从就绪队列中删除, 并没有从 event_loop 中删除
// 否则删除该事件
if (ev->ev_events & EV_PERSIST)
event_queue_remove(base, ev, EVLIST_ACTIVE);
else
// 从所有队列中删除该事件
event_del(ev);
/* Allows deletes to work */
ncalls = ev->ev_ncalls;
ev->ev_pncalls = &ncalls;
while (ncalls) {
ncalls--;
ev->ev_ncalls = ncalls;
(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
if (event_gotsig || base->event_break)
return;
}
}
}
- 从优先级队列头部(也就是activequeues[0])开始循环, 只要该优先级队列不为空, 就退出循环, 执行下面的步骤.
- 从优先级队列中一个个取出就绪事件, 如果是永久事件则只从就绪队列中删除, 否则直接从所有队列中删除该事件
- 接着根据注册事件设置的次数, 调用多少次的回调函数.
思路其实很容易理解. 但这里有一点需要提醒, 因为每次激活都是从优先级为 0 的队列寻找, 一旦找到不为空的就会退出, 所以可能数值越大的就可能会被饿死. 能看出来, 数值越小其实优先级越高.
总结
如果你现在对libevent有了一定的认识后, 相信分析激活功能应该已经很轻松了才是.
- 高优先级(数值大的)可能会被饿死.