在前面的章节我们提到event_base_loop中会调用具体的io复用机制的事件等待以及分发函数evsel->dispatch,然后调用event_process_active处理已经激活的事件。
我们看到epoll_dispatch中调用了一个evmap_io_active函数,这个函数会将激活的事件插入到已激活的事件列表中
event_queue_insert函数才正真将事件插入到已激活事件队列中:
对于epoll而言,dispatch就是epoll_dispatch,我们看一下它的执行流程
// 事件分发
static int
epoll_dispatch(struct event_base *base, struct timeval *tv)
{
struct epollop *epollop = base->evbase;
struct epoll_event *events = epollop->events;
int i, res;
long timeout = -1;
if (tv != NULL) {
timeout = evutil_tv_to_msec(tv);
if (timeout < 0 || timeout > MAX_EPOLL_TIMEOUT_MSEC) {
/* Linux kernels can wait forever if the timeout is
* too big; see comment on MAX_EPOLL_TIMEOUT_MSEC. */
timeout = MAX_EPOLL_TIMEOUT_MSEC;
}
}
// 暂时不用管下面两个函数的调用
epoll_apply_changes(base);
event_changelist_remove_all(&base->changelist, base);
EVBASE_RELEASE_LOCK(base, th_base_lock);
// 等待事件发生,res存放事件发生的个数
res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
// 出错
if (res == -1) {
if (errno != EINTR) {
event_warn("epoll_wait");
return (-1);
}
return (0);
}
event_debug(("%s: epoll_wait reports %d", __func__, res));
EVUTIL_ASSERT(res <= epollop->nevents);
// 遍历所有触发的事件
for (i = 0; i < res; i++)
{
int what = events[i].events;
short ev = 0;
if (what & (EPOLLHUP|EPOLLERR))
{
// 有错误发生
ev = EV_READ | EV_WRITE;
}
else
{
// 可读
if (what & EPOLLIN)
ev |= EV_READ;
// 可写
if (what & EPOLLOUT)
ev |= EV_WRITE;
}
if (!ev)
continue;
// 激活io事件映射表中的事件处理器
evmap_io_active(base, events[i].data.fd, ev | EV_ET);
}
// 如果所有的事件都被触发了,表示事件数组的大小还是太小了,需要扩展事件数组的大小
if (res == epollop->nevents && epollop->nevents < MAX_NEVENT) {
/* We used all of the event space this time. We should
be ready for more events next time. */
int new_nevents = epollop->nevents * 2;
struct epoll_event *new_events;
new_events = mm_realloc(epollop->events,
new_nevents * sizeof(struct epoll_event));
if (new_events) {
epollop->events = new_events;
epollop->nevents = new_nevents;
}
}
return (0);
}
我们看到epoll_dispatch中调用了一个evmap_io_active函数,这个函数会将激活的事件插入到已激活的事件列表中
/*
* 激活io事件映射表中的事件,然后插入到已激活事件队列中
*/
void
evmap_io_active(struct event_base *base, evutil_socket_t fd, short events)
{
struct event_io_map *io = &base->io;
struct evmap_io *ctx;
struct event *ev;
#ifndef EVMAP_USE_HT
EVUTIL_ASSERT(fd < io->nentries);
#endif
GET_IO_SLOT(ctx, io, fd, evmap_io);
EVUTIL_ASSERT(ctx);
TAILQ_FOREACH(ev, &ctx->events, ev_io_next) {
if (ev->ev_events & events)
event_active_nolock(ev, ev->ev_events & events, 1);
}
}
event_active_nolock函数的过程如下:
/*
* 非阻塞的激活事件,并将它存放于己激活事件列表中
*/
void
event_active_nolock(struct event *ev, int res, short ncalls)
{
struct event_base *base;
event_debug(("event_active: %p (fd "EV_SOCK_FMT"), res %d, callback %p",
ev, EV_SOCK_ARG(ev->ev_fd), (int)res, ev->ev_callback));
/* We get different kinds of events, add them together */
// 如果本事件已经存在于已激活事件列表中,那么就返回
if (ev->ev_flags & EVLIST_ACTIVE) {
ev->ev_res |= res;
return;
}
base = ev->ev_base;
EVENT_BASE_ASSERT_LOCKED(base);
ev->ev_res = res;
// 如果当前事件的优先级小于event_base的运行时优先级
// 就让event_base跳过本次循环,进行下一次循环
if (ev->ev_pri < base->event_running_priority)
base->event_continue = 1;
// 如果是信号事件
if (ev->ev_events & EV_SIGNAL) {
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
if (base->current_event == ev && !EVBASE_IN_THREAD(base)) {
++base->current_event_waiters;
EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
}
#endif
ev->ev_ncalls = ncalls;
ev->ev_pncalls = NULL;
}
// 把被激活的事件插入到已激活事件列表
event_queue_insert(base, ev, EVLIST_ACTIVE);
if (EVBASE_NEED_NOTIFY(base))
evthread_notify_base(base);
}
event_queue_insert函数才正真将事件插入到已激活事件队列中:
/*
* 将事件处理器添加到各种事件队列中
* 将io事件处理器和信号事件处理器插入注册事件队列
* 将定时器插入通用定时器队列或时间堆
* 将被激活的事件处理器添加到活动事件队列中
*/
static void
event_queue_insert(struct event_base *base, struct event *ev, int queue)
{
EVENT_BASE_ASSERT_LOCKED(base);
// 避免重复插入
if (ev->ev_flags & queue) {
/* Double insertion is possible for active events */
if (queue & EVLIST_ACTIVE)
return;
event_errx(1, "%s: %p(fd "EV_SOCK_FMT") already on queue %x", __func__,
ev, EV_SOCK_ARG(ev->ev_fd), queue);
return;
}
// 增加event_base拥有的事件处理器的数量
if (~ev->ev_flags & EVLIST_INTERNAL)
base->event_count++;
// 标记该事件处理器已经被处理过
ev->ev_flags |= queue;
// 根据不同的事件插入到不同的队列中
switch (queue) {
// 将io事件处理器或信号事件处理器插入注册事件队列
case EVLIST_INSERTED:
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: {
if (is_common_timeout(&ev->ev_timeout, base)) {
struct common_timeout_list *ctl =
get_common_timeout_list(base, &ev->ev_timeout);
insert_common_timeout_inorder(ctl, ev);
} else
min_heap_push(&base->timeheap, ev);
break;
}
default:
event_errx(1, "%s: unknown queue %x", __func__, queue);
}
}