异想天开

What's the true meaning of light, Could you tell me why

启动分析-nginx源码阅读3

日期:2014-05-26 17:04:11
  
最后更新日期:2015-09-27 16:06:37
一句废话,在不同的阶段对某样事物不同的理解,是合理的,并且也是正常的。很多人的做法是,在成长后抹去成长进阶的过程中的痕迹,故意让后人观之,赞之,膜拜之,仿佛大神就是空中楼阁树立一般。
这里的启动分析的部分仅涉及是nginx怎么建立模块上下文。从架构上看,标准的nginx的模块按功能可分event模块,http模块和mail模块。nginx启动时,ngx_init_cycle会执行核心模块上下文的create_conf函数。event模块,http模块和mail模块各有一个模块类型为NGX_CORE_MODULE核心模块。实际上查看源码发现这些核心模块的create_conf的为空。nginx对于创建模块上下文结构时,是当真正用到的时候才会创建,也就是将创建过程放到指令的钩子函数里面,配置该指令才会执行。

问题一:nginx有多少个核心模块?
不同的nginx的有所不同,在官方nginx-1.4.4源码目录匹配搜索type为NGX_CORE_MODULE的模块。
[code lang="cpp"]
find ./ -regex ".*\.c" -print | xargs grep -onE "NGX_CORE_MODULE"
[/code]
log模块,http模块,mail模块以及event模块都是核心模块。
注:
所有的模块在objs/ngx_modules.c里面有个全局数组。搜索字符串这里可以这样grep NGX_CORE_MODULE *.c -R,简单粗暴。

问题二:为什么模块的ngx_module_s结构有两个表示索引的变量ctx_index,index?
index的值是从0开始自增的,一个模块一个index。ctx_index是用来区分相同类型下的模块,如http模块有好几个,则让他们的ctx_index从0开始自增。用ctx_index的意图是,比如对于http模块而言,先初始化http的核心模块,再初始化其他http模块。
注:
在nginx的模块函数中,需要获取当前模块相关的一些值,比如模块上下文,模块的server配置,location配置等。若需要获得当前模块上下文,调用ngx_http_get_module即可。
r_ctx = ngx_http_get_module_ctx(r, ngx_http_req_status_module);
实际上它的宏的定义为:
#define ngx_http_get_module_ctx(r, module) (r)->ctx[module.ctx_index]
这里ctx_index名字即直观表示了该特定模块的索引的意思。

问题三:命令的钩子函数的conf参数是怎么得到的?
命令类型如下:
[code lang="cpp"]
struct ngx_command_s {
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
};
[/code]
1.ngx_cycle_s里面有个成员为每个模块分配一个指针的空间,用来指示模块配置上下文的地址。ngx_init_cycle中初始为null,因为该空间是模块自己申请的。
2.ngx_conf_parse解析配置文件时,ngx_conf_handler中回掉钩子函数。若是main级别的配置项,则conf为指向指针变量的二级指针。否则则为模块配置上下文的对应级别的配置指针。
解析
[code lang="cpp"]
http{
...
}
[/code]
为例,当解析到http时,该级别为main,对应的钩子函数ngx_http_block负责创建自己的模块配置上下文即ngx_http_conf_ctx_t的存储空间,然后将该地址存储于http模块的ctx上,因为这里会修改ctx,故conf传进来的是ctx的地址的指针参数。ngx_http_block同时还会分配所有http模块的main_conf,srv_conf,loc_conf级别的指针存储空间,对应级别的上下文,还是模块自己的钩子函数创建。
[code lang="cpp"]
confp = *(void **) ((char *) cf->ctx + cmd->conf);
[/code]
根据命令cmd->conf算出偏移到配置级别的首地址。conf值初始化偏移值的计算方式:
[code lang="cpp"]
#define NGX_HTTP_MAIN_CONF_OFFSET offsetof(ngx_http_conf_ctx_t, main_conf)
#define NGX_HTTP_SRV_CONF_OFFSET offsetof(ngx_http_conf_ctx_t, srv_conf)
#define NGX_HTTP_LOC_CONF_OFFSET offsetof(ngx_http_conf_ctx_t, loc_conf)
[/code]
再取得对应模块配置的上下文:
[code lang="cpp"]
conf = confp[ngx_modules[i]->ctx_index];
[/code]
这里的逻辑可以见ngx_http_block函数。