前面讲过ngx_event_core_module模块的init_process函数ngx_event_process_init会为每个监听套接字的读事件注册处理函数ngx_event_accept,本篇就学习一下在ngx_event_accept函数中到底进行了哪些工作。
/* event/ngx_event_accept.c */
/* 监听套接字的读事件处理函数
* param ev: 事件指针
*/
void ngx_event_accept(ngx_event_t *ev)
{
ngx_uint_t instance, accepted;
socklen_t len;
struct sockaddr *sa;
ngx_err_t err;
ngx_log_t *log;
ngx_pool_t *pool;
ngx_socket_t s;
ngx_event_t *rev, *wev;
ngx_connection_t *c, *ls;
ngx_event_conf_t *ecf;
ngx_accept_log_ctx_t *ctx;
// 获取ngx_event_core_module模块的配置信息ecf
ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
// 如果事件处理模型的标志包含NGX_USE_RTSIG_EVENT
// 置ev->available为1
ev->available = 1;
} else if (!(ngx_event_flags & NGX_HAVE_KQUEUE_EVENT)) {
// 如果事件处理模型的标志不包含NGX_HAVE_KQUEUE_EVENT和NGX_USE_RTSIG_EVENT
// 置ev->available为配置的multi_accept
ev->available = ecf->multi_accept;
}
// 获取事件对应的连接ls
ls = ev->data;
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
"accept on %s, ready: %d",
ls->listening->addr_text.data, ev->available);
ev->ready = 0;
accepted = 0;
pool = NULL;
do {
if (pool == NULL) {
// 如果pool为空
// 创建大小为ls->listening->pool_size的内存池pool
if (!(pool = ngx_create_pool(ls->listening->pool_size, ev->log))) {
return;
}
}
// 从内存池pool中申请一个大小ls->listening->socklen的内存空间sa,
// 我们知道这个内存空间是用来存放套接字地址结构的
if (!(sa = ngx_palloc(pool, ls->listening->socklen))) {
ngx_destroy_pool(pool);
return;
}
// 从内存池申请一个ngx_log_t结构体大小的内存空间log
if (!(log = ngx_palloc(pool, sizeof(ngx_log_t)))) {
ngx_destroy_pool(pool);
return;
}
// 将ls->log拷贝至log, 并置pool->log为log;
// 从这里我们可以看出pool与连接ls其实是使用的相同日志,
// 但是却没有直接置pool->log = ls->log,
// 我的看法是避免两者任意一个的销毁操作也会对log进行释放,
// 导致另一个的log无法使用
ngx_memcpy(log, ls->log, sizeof(ngx_log_t));
pool->log = log;
// 从内存池pool中申请一个ngx_accept_log_ctx_t结构体大小的内存