开始分析函数main->ngx_master_process_cycle
ngx_master_process_cycle
首先设置信号屏蔽sigprocmask,然后设置master进程title
然后创建子进程调用
ngx_start_worker_processes(cycle,ccf->worker_processes, NGX_PROCESS_RESPAWN)
/*
* cycle是在main创建的
* n 表示需要创建多少个进程worker_process
* type 为-3 NGX_PROCESS_RESPAWN
*/
static void
ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
{
ngx_int_t i;
ngx_channel_t ch;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
ch.command = NGX_CMD_OPEN_CHANNEL;
//for循环就是为了创建三个进程
for (i = 0; i < n; i++) {
cpu_affinity = ngx_get_cpu_affinity(i);
//主要是设置ngx_process和子进程在该数组中的索引
//其中fork完子进程后,会调用ngx_worker_process_cycle(cycle, NULL)
ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL,
"worker process", type);
ch.pid = ngx_processes[ngx_process_slot].pid;
ch.slot = ngx_process_slot;
ch.fd = ngx_processes[ngx_process_slot].channel[0];
//主要是把ch信息写到前面的子进程里面去,每个子进程都可以进行通信,同时任意父子进程也可以进行通信
ngx_pass_open_channel(cycle, &ch);
}
}
函数主要是根据需要创建woker_process个数来创建多少个进程(for循环),子进程函数为ngx_worker_process_cycle,然后把子进程和父进程通信的socketpair通信句柄传递给前面创建的子进程,channel主要是父进程和子进程进行通信,同时该功能还可以子进程和子进程进行通信,貌似子进程和子进程没有通过channel通信。ngx_pass_open_channel主要把刚刚创建子进程的channel信息写到前面已经创建的子进程中去。
然后master进程fork子进程调用ngx_worker_process_cycle
ngx_worker_process_cycle(cycle, NULL)
此函数就是子进程的主要服务代码,包含了事件初始化、事件触发、事件处理。分析两个主要函数:
ngx_worker_process_init(cycle, 1)//子进程初始化
ngx_process_events_and_timer(cycle)//事件触发和事件处理
其中区别master和worker进程标识字段是变量ngx_process
master NGX_PROCESS_MASTER
worker NGX_PROCESS_WORKER
那么先来分析事件初始化函数
ngx_worker_process_init(cycle, 1)
函数做了如下几件事情
1 设置进程权限(setpriority(PRIO_PROCESS,0, ccf->priority)
2 设置软硬fd连接数(setrlimit(RLIMIT_NOFILE,&rlmt))
3 设置进程core文件大小(setrlimit(RLIMIT_CORE,&rlimit))
4 设置用户组…
5 更改工作目录(chdir)
6 调用进程模块中的init_process函数,来初始化每一个模块的进程初始化回调
for (i = 0; ngx_modules[i]; i++) {
//在子进程创建后,调用每一个模块的初始化进程函数init_process
if (ngx_modules[i]->init_process) {
if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
exit(2);
}
}
}
其中这里涉及到ngx_event_core_module事件模块的的初始化,先说下模块函数回调过程
模块定义三个回调函数分别如下:
struct ngx_module_s{
…..
ngx_int_t (*init_master)(ngx_log_t *log);
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
ngx_int_t (*init_process)(ngx_cycle_t *cycle);
…….
}
其中init_master现在还没有使用。
init_module是在ngx_init_cycle函数中调用的
ngx_cycle_t* ngx_init_cycle(ngx_cycle_t *old_cycle)
{
……….
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->init_module) {
if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
/* fatal */
exit(1);
}
}
}
…………
}
init_process是在ngx_worker_process_init中调用的
static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority)
{
……..
for (i = 0; ngx_modules[i]; i++) {
//在子进程创建后,调用每一个模块的初始化进程函数init_process
if (ngx_modules[i]->init_process) {
if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
/* fatal */
exit(2);
}
}
}
………
}
事件的初始化调用ngx_event_core_module 模块的init_module和init_process函数,首先分析init_module因为init_module是在init_process函数前面调用。其中
static ngx_int_t ngx_event_module_init(ngx_cycle_t*cycle主要是做一些valid验证
然后分析init_process回调函数,相应的函数为
static ngx_int_t ngx_event_process_init(ngx_cycle_t* cycle)
{
…………………
//master是用户设置master_process on 或者配置没有设置。默认会被设置为1
//worker_processes 是用户配置的用户进程个数
//accept_mutex 是用户配置的是否开启使用accept_mutex on/off 默认是1 开启状态
if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) {
ngx_use_accept_mutex = 1;//是否开启负载均衡
ngx_accept_mutex_held = 0;//设置进程没有获取mutex
ngx_accept_mutex_delay = ecf->accept_mutex_delay;//epoll_wait的超时时间,用户配置的值
} else {
ngx_use_accept_mutex = 0;
}
……
ngx_event_timer_init(cycle->log)//初始化超时红黑树
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_EVENT_MODULE) {
continue;
}
//判断使用哪一个网络事件模块是在ngx_event_core_init_conf设置use
if (ngx_modules[m]->ctx_index != ecf->use) {
continue;
}
module = ngx_modules[m]->ctx;
//调用epoll模块的初始化函数, 主要是把ngx_event_actions 指向 epoll的操作函数
//调用模块的初始化函数
if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
/* fatal */
exit(2);
}
break;
}
……
//分配连接
cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);
//分配读事件
cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log);
//分配写事件
cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log);
do {
i--;
c[i].data = next;
//每一个连接都有一个读事件和一个写事件
c[i].read = &cycle->read_events[i];
c[i].write = &cycle->write_events[i];
c[i].fd = (ngx_socket_t) -1;
//这个数组是一个反向链,
next = &c[i];
#if (NGX_THREADS)
c[i].lock = 0;
#endif
} while (i);
cycle->free_connections = next;//free链表指向connection链表
cycle->free_connection_n = cycle->connection_n;//设置connection个数
ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++) {
//申请一块连接内存ngx_connection_t
c = ngx_get_connection(ls[i].fd, cycle->log);
if (c == NULL) {
return NGX_ERROR;
}
c->log = &ls[i].log;
c->listening = &ls[i];
ls[i].connection = c;//设置listening的connection为监听的connection,用于对事件进行监听
rev = c->read;
rev->log = c->log;
//设置accept为1表示此connect是listen套接字
rev->accept = 1;
//设置连接rev回调为ngx_event_accept,当一个连接进行连接的时候就会调用这个函数
rev->handler = ngx_event_accept;
//因为如果用多进程共享锁,那么后面worker进程会通过加锁方式来对这些监听事件互斥访问
//如果进程负载均衡那么就不加入监控事件中去
if (ngx_use_accept_mutex) {
continue;
}
if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
if (ngx_add_conn(c) == NGX_ERROR) {
return NGX_ERROR;
}
} else {
if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
return NGX_ERROR;
}
}
}
static ngx_int_t ngx_event_process_init(ngx_cycle_t*cycle)函数主要完成以下功能
1 开启对监听套接字的负载均衡
2 初始化超时红黑树
3 对使用的io复用模型初始化(epoll模型)
4 分配连接(cycle->connections)、分配读事件(cycle->read_events)、分配写事件(cyvle->write_events)
5 一个连接配置一个读事件和一个写事件
6 对监听分配connection,并且保存在cycle->listening.connection中,同时设置rev事件的handler为ngx_event_accept
然后再回到ngx_worker_process_init函数,最后调用ngx_add_channel_event,此函数主要是把和父进程通信的sockpair加入到epoll网络事件循环中去,方便父子进程之间进行通信
然后继续分析第二个函数
ngx_process_events_and_timers(cycle)
{
……………
//超时有两种算法
if (ngx_timer_resolution) {
//第一种是定时,epoll_wait 时间设置成infinite用定时器来激活epoll_wait
timer = NGX_TIMER_INFINITE;
flags = 0;
} else {
//默认是第二种
//第二种用最小超时时间,获取最小超时时间方法就是从红黑超时树中获取
timer = ngx_event_find_timer();
flags = NGX_UPDATE_TIME;
}
if (ngx_use_accept_mutex) {
if (ngx_accept_disabled > 0) {
ngx_accept_disabled--;
} else {
//如果能拿到那么就已经加入到epoll中去了
if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
return;
}
//如果加锁成功,那么事件会移后处理
if (ngx_accept_mutex_held) {
flags |= NGX_POST_EVENTS;
} else {
if (timer == NGX_TIMER_INFINITE || timer > ngx_accept_mutex_delay)
{
timer = ngx_accept_mutex_delay;
}
}
}
}
/*
* cycle
* timer epoll_wait设置的超时时间
* flags 设置的标志,用于表示收到网络事件后的操作,比如移后处理。
* 此函数映射到epoll复用模块的ngx_epoll_process_events函数,后面会分析
*/
(void) ngx_process_events(cycle, timer, flags)
/*函数完成的操作有
*1 如果该进程抢占到监听套接字并且接受连接读事件是一个accept sock,并且flag设置NGX_POST_EVENT延后处理,那么就把连接rev加入ngx_posts_accept_events,如果是普通连接加入到ngx_post_events,否则就直接调用rev->handler方法
*2 如果该进程抢占到监听套接字,设置flag为延后处理,那么就把该wev事件加入到ngx_post_events链表里面,如果没有进行延后处理,那么就直接调用写的回调函数
wev->handler(wev)
*
*/
//如果post accept事件链表不为空,那么就进行处理
if (ngx_posted_accept_events) {
ngx_event_process_posted(cycle, &ngx_posted_accept_events);
}
//解锁,accept用完了
if (ngx_accept_mutex_held) {
ngx_shmtx_unlock(&ngx_accept_mutex);
}
//处理超时
if (delta) {
ngx_event_expire_timers();
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"posted events %p", ngx_posted_events);
//处理已经连接事件
if (ngx_posted_events) {
if (ngx_threaded) {
ngx_wakeup_worker_thread(cycle);
} else {
ngx_event_process_posted(cycle, &ngx_posted_events);
}
}
}
一开始每一个进程都是都是加入到监听套接口到epoll中去,然后开始的事件肯定是连接事件,那么也就是调用rev->handler,此时的handler真实回调函数为ngx_event_accept,那么我们就开始分析ngx_event_accept。
ngx_event_accept函数主要完成如下几点功能
1 accept获取client连接
2 设置ngx_accept_disabled= ngx_cycle->connection_n/8 – ngx_cycle->free_connection_n
3 ngx_get_connection(s, ev->log)给client连接分配connection
4 连接初始化
5 调用accept sock的ls->handler此函数为ngx_http_init_connection
然后接着分析ngx_http_init_connection
函数主要是设置rev和wev事件的回调函数,如果读事件已经准备好了,那么处理,如果没有准备好,那么就加入epoll事件中,如果在epoll事件中有数据已经读取完毕,还是会调用rev->handler,也就是ngx_http_init_request函数。
可以看到函数处理流程相应的client connection的rev和wev handler的变化情况表
Func | rev->handler | wev->handler |
ngx_http_init_connection | ngx_http_init_request | ngx_http_empty_handler |
ngx_http_init_request | ngx_http_process_request_line | ngx_http_empty_handler |
ngx_http_process_request_line | ngx_http_process_request_headers | ngx_http_empty_handler |
处理请求line和header之后,调用ngx_http_process_request
static void ngx_http_process_request(ngx_http_request_t*r)
然后调用ngx_http_handler()
然后调用ngx_http_core_run_phase()
此函数会回调每一个模块注册的函数
void
ngx_http_core_run_phases(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_phase_handler_t *ph;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
ph = cmcf->phase_engine.handlers;
while (ph[r->phase_handler].checker) {
rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
if (rc == NGX_OK) {
return;
}
}
}