nginx-0.8.38源码探秘(四)

本文档的Copyleft归L.L所有,使用GPL发布,可以自由转载,转载时请务必以超链接形式标明文章原始出处,严禁用于任何商业用途。

email: [email protected]
来源: http://blog.csdn.net/ccdd14

 

 

回到ngx_init_cycle函数,遍历NGX_CORE_MODULE模块,调用它们注册的init_conf钩子。只有ngx_core_module模块注册了这个钩子-----ngx_core_module_init_conf,初始化ngx_core_conf_t结构,获取用户名,用户id,组id,设置lockfile文件。

ngx_open_listening_sockets函数创建套接口,设置套接口选项,如果不使用AIO,则设置为非阻塞套接口,最后listen。

接着遍历所有模块注册的init_module钩子,只有ngx_event_core_module模块注册了------ngx_event_module_init,输出选择使用的事件模型,判断worker_connections是否超过限制,初始化几个全局变量ngx_timer_resolution,ngx_accept_mutex_ptr,ngx_random_number。

最后将结果返回给ngx_cycle,终于将ngx_init_cycle分析完成。

 

回到main的怀抱里。ngx_init_signals安装信号处理函数,ngx_daemon将nginx设置为后台进程。

最后看看ngx_master_process_cycle,进程的初始化工作在这里完成。

ngx_start_worker_processes功能是启动工作者线程。ngx_spawn_process创建unix域套接口,用于父子进程间的通信。进程信息存储在ngx_processes中。启动子进程函数-----ngx_worker_process_cycle,重要的工作在ngx_worker_process_init里面完成。设置进程环境,进程优先级,进程资源限制,进程cpu掩码,接着初始化所有模块的init_process钩子,其中ngx_event_core_module注册的ngx_event_process_init是非常重要的一个钩子(很多模块都没注册这个钩子)。

ngx_event_process_init根据默认情况初始化ngx_use_accept_mutex = 1,ngx_accept_mutex_held = 0,ngx_accept_mutex_delay = 500,然后创建了用于事件的定时器红黑树,接着遍历NGX_EVENT_MODULE模块的context,调用action的init钩子,epoll模型下是ngx_epoll_init函数,看看epoll模块注册的其他action。

ngx_event_module_t ngx_epoll_module_ctx = { &epoll_name, ngx_epoll_create_conf, /* create configuration */ ngx_epoll_init_conf, /* init configuration */ { ngx_epoll_add_event, /* add an event */ ngx_epoll_del_event, /* delete an event */ ngx_epoll_add_event, /* enable an event */ ngx_epoll_del_event, /* disable an event */ ngx_epoll_add_connection, /* add an connection */ ngx_epoll_del_connection, /* delete an connection */ NULL, /* process the changes */ ngx_epoll_process_events, /* process the events */ ngx_epoll_init, /* init the events */ ngx_epoll_done, /* done the events */ } }; 

ngx_epoll_init创建了epoll句柄,添加aio事件,设置ngx_event_flags=NGX_USE_CLEAR_EVENT | NGX_USE_GREEDY_EVENT | NGX_USE_EPOLL_EVENT。然后,ngx_event_process_init函数初始化ngx_cycle里的connections,read_events(注意rev[i].instance = 1),write_events。它们构建了连接,读写事件的数组。然后对每个listen的socket都创建一个空闲连接,注册连接的读事件handler,rev->handler = ngx_event_accept,最后将事件添加到epoll中(实际上ngx_use_accept_mutex = 1,所以没有在这个地方添加事件)。

ngx_add_channel_event将父子进程的unix域套接口的fd加入到epoll事件中,注册ev->handler = ngx_channel_handler,接收父进程的指令信息,做相应的处理,如退出。

完成子进程的初始化后(ngx_worker_process_init),进入子线程的主循环,关键函数是ngx_process_events_and_timers,事件的添加和处理都在这个函数里完成,详细分析一下这个函数。

small;">void ngx_process_events_and_timers(ngx_cycle_t *cycle) { ngx_uint_t flags; ngx_msec_t timer, delta; //如果没有配置timer_resolution指令,ngx_timer_resolution==0 if (ngx_timer_resolution) { timer = NGX_TIMER_INFINITE; flags = 0; } else { //ngx_event_find_timer获取最小的timer,然后计算和当前时间(ngx_current_msec)的差 timer = ngx_event_find_timer(); flags = NGX_UPDATE_TIME; #if (NGX_THREADS) if (timer == NGX_TIMER_INFINITE || timer > 500) { timer = 500; } #endif } //默认ngx_use_accept_mutex==1 if (ngx_use_accept_mutex) { if (ngx_accept_disabled > 0) { ngx_accept_disabled--; } else { //加锁ngx_accept_mutex,将connect的read事件添加到epoll事件中, //置ngx_accept_mutex_held=1 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; } } } } delta = ngx_current_msec; //更新nginx当前时间,处理epoll事件,将读写事件分别加入到不同的队列里 (void) ngx_process_events(cycle, timer, flags); //得到处理epoll事件花费的时间,没有事件处理delta==0 delta = ngx_current_msec - delta; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "ngx_process_events_and_timers timer delta: %M", delta); //如果ngx_posted_accept_events队列里有事件,立即从队列里取出ev->handler处理,直到队列为空 if (ngx_posted_accept_events) { ngx_event_process_posted(cycle, &ngx_posted_accept_events); } //解锁ngx_accept_mutex if (ngx_accept_mutex_held) { ngx_shmtx_unlock(&ngx_accept_mutex); } if (delta) { //查看是否有超时事件,有则立即调用ev->handler处理,并将定时器删除,以免造成事件饥饿 ngx_event_expire_timers(); } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "posted events %p", ngx_posted_events); //如果ngx_posted_events队列有事件需要处理,立即从队列里取出ev->handler处理,直到队列为空 if (ngx_posted_events) { if (ngx_threaded) { ngx_wakeup_worker_thread(cycle); } else { ngx_event_process_posted(cycle, &ngx_posted_events); } } }

epoll注册的事件处理函数是ngx_epoll_process_events,然后下面几个语句一直不是很明白,希望有朋友帮忙解答:

//为什么要这么计算得到instance,c instance = (uintptr_t) c & 1; c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1); rev = c->read; //instance的具体含义是什么?the stale even怎么理解? if (c->fd == -1 || rev->instance != instance) { /* * the stale event from a file descriptor * that was just closed in this iteration */ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "epoll: stale event %p", c); continue; } 

ngx_start_worker_processes调用的最后一个函数是ngx_pass_open_channel,功能是将channel的fd传送给子进程。至此,工作者线程初始化和启动完成。

ngx_start_cache_manager_processes函数启动文件cache管理进程。先判断 是否有注册pathes的manager钩子,目前有ngx_http_proxy_module模块,ngx_http_fastcgi_module模块注册了manager,loader,分别在下面的两个钩子里注册的:

//ngx_http_proxy_module { ngx_string("proxy_cache_path"), NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, ngx_http_file_cache_set_slot, 0, 0, &ngx_http_proxy_module }, //ngx_http_fastcgi_module { ngx_string("fastcgi_cache_path"), NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, ngx_http_file_cache_set_slot, 0, 0, &ngx_http_fastcgi_module }, 

看看ngx_http_file_cache_set_slot钩子里注册的函数:cache->path->manager = ngx_http_file_cache_manager,cache->path->loader = ngx_http_file_cache_loader。然后启动cache manager进程和cache loader进程。注册的子进程函数都是ngx_cache_manager_process_cycle,先初始化进程环境,接着关闭所有socket,主循环是对ngx_process_events_and_timers的调用。关键是传给子进程的两个不同参数:

static ngx_cache_manager_ctx_t ngx_cache_manager_ctx = { ngx_cache_manager_process_handler, "cache manager process", 0 }; static ngx_cache_manager_ctx_t ngx_cache_loader_ctx = { ngx_cache_loader_process_handler, "cache loader process", 60000 }; 

ngx_cache_manager_process_handler主要功能就是调用注册的manager钩子,而ngx_cache_loader_process_handler则是调用注册的loader钩子。

最后进入父进程的主循环,主要就是信号的处理,更新nginx当前时间,这个不再细说。

哈......nginx的初始化流程分析结束。

你可能感兴趣的:(timer,manager,cache,Module,Descriptor,events)