1、在第五篇的末尾,曾提到
(子进程)将把自己从父进程继承的ngx_channel[1](channel[0]被用于父进程或其它子进程写消息)加入到读事件监听集里。
实现这个动作的,就是ngx_add_channel_event函数。现在让我们从这个角度来观察一下nginx的事件监听机制。
这是ngx_add_channel_event(位于ngx_event.c)的主要逻辑代码:
ngx_int_t
ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event,
ngx_event_handler_pt handler)
{
ngx_event_t *ev, *rev, *wev;
ngx_connection_t *c;
c = ngx_get_connection(fd, cycle->log);
//获取事件ev...
ev = (event == NGX_READ_EVENT) ? rev : wev;
ev->handler = handler;
if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
if (ngx_add_conn(c) == NGX_ERROR) {
ngx_free_connection(c);
return NGX_ERROR;
}
} else {
if (ngx_add_event(ev, event, 0) == NGX_ERROR) {
ngx_free_connection(c);
return NGX_ERROR;
}
}
return NGX_OK;
}
 这里的ngx_add_conn 和ngx_add_event函数,都是第六章中所提到的ngx_event_actions_t 结构体中定义的函数指针。这里主要关注epoll模型。若定义使用epoll模型,则这里的ngx_add_conn 和ngx_add_event将对应ngx_epoll_module.c中的ngx_epoll_add_connection函数和ngx_epoll_add_event函数。
2、关于epoll
-
关于ngx_epoll_add_connection函数:
ngx_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); 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) { 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; }
关键代码只有一句,
epoll_ctl(ep, EPOLL_CTL_ADD, c->fd, &ee)
这里,使用了linux下epoll_ctl注册与c->fd相关联的读事件和写事件。
-
关于ngx_add_event,逻辑和ngx_epoll_add_connection差不多,也是注册相应flag的epoll事件:
ee.events = events | (uint32_t) flags; ee.data.ptr = (void *) ((uintptr_t) c | ev->instance); if (epoll_ctl(ep, op, c->fd, &ee) == -1) { return NGX_ERROR; }
网友评论