选择完成最适合的io复用机制之后,就要开始进行初始化设置,即调用eventop的init回调函数,以epoll为例,epoll_init的定义如下:
// epoll初始化
static void *
epoll_init(struct event_base *base)
{
// epoll的文件描述符
int epfd;
// 用于存放epoll的文件描述符以及一些事件
struct epollop *epollop;
/* Initialize the kernel queue. (The size field is ignored since
* 2.6.8.) */
// 创建epoll文件描述符
// 这里直接使用了底层的系统调用,而不是linux提供的api接口
if ((epfd = epoll_create(32000)) == -1) {
if (errno != ENOSYS)
event_warn("epoll_create");
return (NULL);
}
// 当调用exec时 关闭该描述符
evutil_make_socket_closeonexec(epfd);
// 创建epollop结构
if (!(epollop = mm_calloc(1, sizeof(struct epollop)))) {
close(epfd);
return (NULL);
}
// 初始化epollop的字段
epollop->epfd = epfd;
/* Initialize fields */
// 初始化epoll事件数组
epollop->events = mm_calloc(INITIAL_NEVENT, sizeof(struct epoll_event));
if (epollop->events == NULL) {
mm_free(epollop);
close(epfd);
return (NULL);
}
epollop->nevents = INITIAL_NEVENT;
// 如果设置了使用changelist,那么就使用changelist
// 使用了changelist可以减少系统调用的次数
if ((base->flags & EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST) != 0 ||
((base->flags & EVENT_BASE_FLAG_IGNORE_ENV) == 0 &&
evutil_getenv("EVENT_EPOLL_USE_CHANGELIST") != NULL))
base->evsel = &epollops_changelist;
// 信号处理器初始化
evsig_init(base);
return (epollop);
}
我们看到epoll_init函数的最后调用了evsig_init,这个函数的作用是初始化信号处理器,它定义如下:
/*
* 信号处理器初始化
*/
int
evsig_init(struct event_base *base)
{
/*
* Our signal handler is going to write to one end of the socket
* pair to wake up our event loop. The event loop then scans for
* signals that got delivered.
*/
/*
* 创建用于通知信号到来的管道
* 当程序受到信号的时候,并不直接处理,而是通过管道将其传递到事件多路分发器中
* 这样信号就能够像其他事件那样可以被统一处理了
*/
if (evutil_socketpair( AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1)
{
#ifdef WIN32
/* Make this nonfatal on win32, where sometimes people
have localhost firewalled. */
event_sock_warn(-1, "%s: socketpair", __func__);
#else
event_sock_err(1, -1, "%s: socketpair", __func__);
#endif
return -1;
}
// 调用exec的时,关闭高套接字
evutil_make_socket_closeonexec(base->sig.ev_signal_pair[0]);
evutil_make_socket_closeonexec(base->sig.ev_signal_pair[1]);
// 设置旧的信号处理函数数组和数量
base->sig.sh_old = NULL;
base->sig.sh_old_max = 0;
// 设置套接字为非阻塞
evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]);
// 事件处理器赋值
event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1],
EV_READ | EV_PERSIST, evsig_cb, base);
base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
// 优先级设置
event_priority_set(&base->sig.ev_signal, 0);
// 保存针对信号的操作(evsigops和epollops一样是一个操作的集合)
base->evsigsel = &evsigops;
return 0;
}