Nginx event核心模块之epoll模块详解(二)
在ngx_epoll_module中关于创建侦听SOCKET以及进程的SPAWN这里就先不讨论了。
以下讨论下epoll模块中各个函数的作用以及关系。
主要是以下这几个函数:
static ngx_int_tngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);//主要用于初始化epoll的基本信息,比如epoll_create函数就在这里有调用。
{
ngx_epoll_conf_t *epcf;
epcf =ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
if (ep == -1) {
ep = epoll_create(cycle->connection_n /2);//创建一个epoll的句柄,cycle->connection_n / 2是告诉内核这个监听的数目一共有多大,出错则返回-1,成功则放回epoll句柄。
……
if (nevents < epcf->events) {
if (event_list) {
ngx_free(event_list);
}
event_list = ngx_alloc(sizeof(structepoll_event) * epcf->events,
cycle->log);//创建事件空间
if (event_list == NULL) {
return NGX_ERROR;
}
}
nevents = epcf->events;//事件最大数量
ngx_io = ngx_os_io;
ngx_event_actions =ngx_epoll_module_ctx.actions;//定义在ngx_event.c中,用于决定event模块中到底是采用epoll还是select以及其他….
#if(NGX_HAVE_CLEAR_EVENT)
ngx_event_flags = NGX_USE_CLEAR_EVENT
#else
ngx_event_flags = NGX_USE_LEVEL_EVENT
#endif
|NGX_USE_GREEDY_EVENT
|NGX_USE_EPOLL_EVENT;
return NGX_OK;
}
static void ngx_epoll_done(ngx_cycle_t*cycle)//关闭epoll
{
if (close(ep) == -1) {//epoll结束的时候close掉
ngx_log_error(NGX_LOG_ALERT,cycle->log, ngx_errno,
"epoll close()failed");
}
ep = -1;//设置为-1,避免再次调用
……..
#if(NGX_HAVE_FILE_AIO)
……
#endif
ngx_free(event_list);//释放事件空间
event_list = NULL;//并把指针致为空
nevents = 0;//事件数量设置为0
}
static ngx_int_tngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event,
ngx_uint_tflags)
{
int op;//操作符EPOLL_CTL_ADD EPOLL_CTL_DEL,EPOLL_CTL_MOD,这里主用是用ADD和MOD
uint32_t events, prev;
ngx_event_t *e;
ngx_connection_t *c;
struct epoll_event ee;
c = ev->data;//程序中一般把ngx_event_t结构中的data部分设置为ngx_connection_t数据
events = (uint32_t) event;//事件,读或者写
if (event == NGX_READ_EVENT) {
e = c->write;
prev = EPOLLOUT;
#if(NGX_READ_EVENT != EPOLLIN)
events = EPOLLIN;
#endif
} else {
e = c->read;
prev = EPOLLIN;
#if(NGX_WRITE_EVENT != EPOLLOUT)
events = EPOLLOUT;
#endif
}//根据event变量设置读写事件,但为什么这里读事件会是写,写会是读呢?
if (e->active) {//查看事件是否accept之后
op = EPOLL_CTL_MOD;
events |= prev;
} else {
op = EPOLL_CTL_ADD;//没激活肯定需要添加
}
ee.events = events | (uint32_t) flags;
ee.data.ptr = (void *) ((uintptr_t) c |ev->instance);//把ngx_connection_t数据添加到epoll_event中去
ngx_log_debug3(NGX_LOG_DEBUG_EVENT,ev->log, 0,
"epoll add event: fd:%dop:%d ev:%08XD",
c->fd, op, ee.events);
if (epoll_ctl(ep, op, c->fd, &ee) ==-1) {//根据操作符对文件描述符做相应操作
ngx_log_error(NGX_LOG_ALERT,ev->log, ngx_errno,
"epoll_ctl(%d, %d)failed", op, c->fd);
return NGX_ERROR;
}
ev->active = 1;
#if 0
ev->oneshot = (flags &NGX_ONESHOT_EVENT) ? 1 : 0;
#endif
return NGX_OK;
}
static ngx_int_tngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event,
ngx_uint_tflags)
int op;
uint32_t prev;
ngx_event_t *e;
ngx_connection_t *c;
struct epoll_event ee;
/*
* when the file descriptor is closed, theepoll automatically deletes
* it from its queue, so we do not need todelete explicitly the event
* before the closing the file descriptor
*/
if (flags & NGX_CLOSE_EVENT) {//close 半关闭状态
ev->active = 0;
return NGX_OK;
}
c = ev->data;//连接数据
if (event == NGX_READ_EVENT) {//客户端读事件,从而服务器写
e = c->write;
prev = EPOLLOUT;
} else {//反之
e = c->read;
prev = EPOLLIN;
}
if (e->active) {//如果连接活动的。则修改
op = EPOLL_CTL_MOD;
ee.events = prev | (uint32_t) flags;
ee.data.ptr = (void *) ((uintptr_t) c |ev->instance);
} else {//反之删除
op = EPOLL_CTL_DEL;
ee.events = 0;
ee.data.ptr = NULL;
}
ngx_log_debug3(NGX_LOG_DEBUG_EVENT,ev->log, 0,
"epoll del event: fd:%dop:%d ev:%08XD",
c->fd, op, ee.events);
if (epoll_ctl(ep, op, c->fd, &ee) ==-1) {//执行连接文件描述符的修改和删除工作
ngx_log_error(NGX_LOG_ALERT,ev->log, ngx_errno,
"epoll_ctl(%d, %d)failed", op, c->fd);
return NGX_ERROR;
}
ev->active = 0;//设置为不可用
return NGX_OK;
}
static ngx_int_tngx_epoll_add_connection(ngx_connection_t *c)
{
struct epoll_event ee;
ee.events = EPOLLIN|EPOLLOUT|EPOLLET;
ee.data.ptr = (void *) ((uintptr_t) c |c->read->instance);//ptr部分一般指向的是ngx_connection_t数据
ngx_log_debug2(NGX_LOG_DEBUG_EVENT,c->log, 0,
"epoll add connection:fd:%d ev:%08XD", c->fd, ee.events);
if (epoll_ctl(ep, EPOLL_CTL_ADD, c->fd,&ee) == -1) {//添加新的文件描述符到epoll数组中
ngx_log_error(NGX_LOG_ALERT, c->log,ngx_errno,
"epoll_ctl(EPOLL_CTL_ADD, %d) failed", c->fd);
return NGX_ERROR;
}
c->read->active = 1;
c->write->active = 1;//设置读写激活
return NGX_OK;
}
static ngx_int_tngx_epoll_del_connection(ngx_connection_t *c,
ngx_uint_tflags)
{
int op;
struct epoll_event ee;
/*
* when the file descriptor is closed theepoll automatically deletes
* it from its queue so we do not need todelete explicitly the event
* before the closing the file descriptor
*/
if (flags & NGX_CLOSE_EVENT) {//close 半关闭状态
c->read->active = 0;
c->write->active = 0;
return NGX_OK;
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT,c->log, 0,
"epoll del connection:fd:%d", c->fd);
op = EPOLL_CTL_DEL;//设置为删除操作
ee.events = 0;
ee.data.ptr = NULL;
if (epoll_ctl(ep, op, c->fd, &ee) ==-1) {//从event数组中删除该文件描述符
ngx_log_error(NGX_LOG_ALERT, c->log,ngx_errno,
"epoll_ctl(%d, %d) failed", op,c->fd);
return NGX_ERROR;
}
c->read->active = 0;
c->write->active = 0;//设置连接不可用
return NGX_OK;
}
staticngx_int_t
ngx_epoll_process_events(ngx_cycle_t*cycle, ngx_msec_t timer, ngx_uint_t flags)
//该函数会调用epoll_wait函数,并且会在进程中循环调用,为epoll核心函数
{
int events;
uint32_t revents;
ngx_int_t instance, i;
ngx_uint_t level;
ngx_err_t err;
ngx_event_t *rev, *wev, **queue;
ngx_connection_t *c;
/* NGX_TIMER_INFINITE == INFTIM */
ngx_log_debug1(NGX_LOG_DEBUG_EVENT,cycle->log, 0,
"epoll timer: %M",timer);
events = epoll_wait(ep, event_list, (int)nevents, timer);//timer数据是根据红黑树的原理进行计算的。以后进行详细讨论
err = (events == -1) ? ngx_errno : 0;//出错时errno获取
if (flags & NGX_UPDATE_TIME ||ngx_event_timer_alarm) {//ngx_current_msec更新
ngx_time_update();
}
if (err) {
if (err == NGX_EINTR) {//中断信号EINTR
if (ngx_event_timer_alarm) {
ngx_event_timer_alarm = 0;
return NGX_OK;
}
level = NGX_LOG_INFO;
} else {//警告信号
level = NGX_LOG_ALERT;
}
ngx_log_error(level, cycle->log,err, "epoll_wait() failed");
return NGX_ERROR;
}//出错退出
if (events == 0) {//相应的事件个数为0,timer时间到
if (timer != NGX_TIMER_INFINITE){//timer不为无限大
return NGX_OK;
}
ngx_log_error(NGX_LOG_ALERT,cycle->log, 0,
"epoll_wait()returned no events without timeout");
return NGX_ERROR;
}
ngx_mutex_lock(ngx_posted_events_mutex);//事件处置互斥
for (i = 0; i < events; i++) {
c = event_list[i].data.ptr;
instance = (uintptr_t) c & 1;
c = (ngx_connection_t *) ((uintptr_t) c& (uintptr_t) ~1);//根据epoll_event.data.ptr获取连接信息
rev = c->read;//客户读请求
if (c->fd == -1 || rev->instance!= instance) {
/*
* the stale event from a filedescriptor
* that was just closed in thisiteration
*/
ngx_log_debug1(NGX_LOG_DEBUG_EVENT,cycle->log, 0,
"epoll: staleevent %p", c);
continue;
}
revents = event_list[i].events;//事件信号,EPOLLIN,EPOLLOUT.....
ngx_log_debug3(NGX_LOG_DEBUG_EVENT,cycle->log, 0,
"epoll: fd:%dev:%04XD d:%p",
c->fd, revents,event_list[i].data.ptr);
if (revents & (EPOLLERR|EPOLLHUP)){//事件信号为错误或挂断
ngx_log_debug2(NGX_LOG_DEBUG_EVENT,cycle->log, 0,
"epoll_wait()error on fd:%d ev:%04XD",
c->fd, revents);
}
#if 0
if (revents &~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
ngx_log_error(NGX_LOG_ALERT,cycle->log, 0,
"strangeepoll_wait() events fd:%d ev:%04XD",
c->fd, revents);
}
#endif
if ((revents & (EPOLLERR|EPOLLHUP))
&& (revents &(EPOLLIN|EPOLLOUT)) == 0)//事件出错挂断和事级读写不同时出现,则设置事件为读写
{
/*
* if the error events werereturned without EPOLLIN or EPOLLOUT,
* then add these flags to handlethe events at least in one
* active handler
*/
revents |= EPOLLIN|EPOLLOUT;
}
if ((revents & EPOLLIN) &&rev->active) {//事件可用且可读,处理事件
if ((flags &NGX_POST_THREAD_EVENTS) && !rev->accept) {//事件没有被accept,这个位设置在event_init阶段
rev->posted_ready = 1;//设置为posted事件
} else {
rev->ready = 1;//否则准备接受事件,进行处理
}
if (flags & NGX_POST_EVENTS) {
queue = (ngx_event_t **)(rev->accept ?
&ngx_posted_accept_events : &ngx_posted_events);//是否为acceptevent,如果是acceptevent,则在主循环中处理,普通的也是如此
ngx_locked_post_event(rev,queue);//把rev添加到queue中
} else {
rev->handler(rev);//事件处理
}
}
wev = c->write;//写事件
if ((revents & EPOLLOUT) &&wev->active) {//事件可用且为EPOLLOUT
if (c->fd == -1 ||wev->instance != instance) {//fd错误
/*
* the stale event from a filedescriptor
* that was just closed in thisiteration
*/
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"epoll:stale event %p", c);
continue;
}
if (flags &NGX_POST_THREAD_EVENTS) {
wev->posted_ready = 1;
} else {
wev->ready = 1;
}
if (flags & NGX_POST_EVENTS) {
ngx_locked_post_event(wev,&ngx_posted_events);//把wev添加到ngx_posted_events队列中
} else {
wev->handler(wev);//事件处理
}
}
}
ngx_mutex_unlock(ngx_posted_events_mutex);//释放锁
return NGX_OK;
}