Nginx源码学习,模块的加载与初始化

一、执行configure

./configure 自动脚本根据configure参数自动生成ngx_modules.c,里面包含了所有模块的声明,并把所有模块维护在ngx_modules[]数组里面。

./configure \

  --prefix=/usr \

  --sbin-path=/usr/sbin/nginx \

  --conf-path=/etc/nginx/nginx.conf \

  --error-log-path=/var/log/nginx/error.log \

  --pid-path=/var/run/nginx/nginx.pid  \

  --lock-path=/var/lock/nginx.lock \

  --user=nginx \

  --group=nginx \

  --with-http_ssl_module \

  --with-http_flv_module \

  --with-http_gzip_static_module \

  --without-http_rewrite_module \

  --http-log-path=/var/log/nginx/access.log \

  --http-client-body-temp-path=/var/tmp/nginx/client/ \

  --http-proxy-temp-path=/var/tmp/nginx/proxy/ \

  --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/

运行自动脚本生成的ngx_modules.c

#include <ngx_config.h>

#include <ngx_core.h>

extern ngx_module_t  ngx_core_module;

extern ngx_module_t  ngx_errlog_module;

extern ngx_module_t  ngx_conf_module;

extern ngx_module_t  ngx_events_module;

extern ngx_module_t  ngx_event_core_module;

extern ngx_module_t  ngx_epoll_module;

extern ngx_module_t  ngx_openssl_module;

。。。 。。。

ngx_module_t *ngx_modules[] = {

    &ngx_core_module,            //模块列表

    &ngx_errlog_module,

    &ngx_conf_module,

    &ngx_events_module,

    &ngx_event_core_module,

    &ngx_epoll_module,

&ngx_openssl_module,

。。。 。。。

NULL

};

 

二、初始化模块

nginx.c中main函数中:

    ngx_max_module = 0;

    for (i = 0; ngx_modules[i]; i++) {

        ngx_modules[i]->index = ngx_max_module++;

    }

ngx_max_module记录模块数,每个模块用唯一的index区别。

 

然后调用ngx_init_cycle,该函数是nginx启动初始化的核心之处,同时模块的配置加载、初始化也在其中完成。 

187     cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));

 188     if (cycle->conf_ctx == NULL) {

 189         ngx_destroy_pool(pool);

 190         return NULL;

 191     }

首先根据ngx_max_module大小申请一块内存池 ,cycle->conf_ctx在这扮演很重要的角色,我们得知ngx_max_modules统计了模块总数,因此可以看出cycle中的conf_ctx将存储每个module的某些信息。接下来的for循环验证了我们的猜想。

214     for (i = 0; ngx_modules[i]; i++) {                                                     

 215         if (ngx_modules[i]->type != NGX_CORE_MODULE) {                                     

 216             continue;                                                                      

 217         }                                             

 219         module = ngx_modules[i]->ctx;                                                      

 221         if (module->create_conf) {                                                         

 222             rv = module->create_conf(cycle);                                

 223             if (rv == NULL) {                                                              

 224                 ngx_destroy_pool(pool);                                                    

 225                 return NULL;          

 226             }                                                                              

 227             cycle->conf_ctx[ngx_modules[i]->index] = rv;                                   

 228         }                                                                                  

 229     }

在for循环中,调用NGX_CORE_MODULE类型模块的ceate_conf回调,创建相应的配置结构存储空间,然后将这个配置结构存储空间的地址保存到conf_ctx数组的对应单元处。寻找正确的对应单元就是通过每个模块的index字段。通过对NGX_CORE_MODULE类型模块的处理,我们暂且猜测conf_ctx数组就是用来存储每个模块的配置结构;利用这个数组,我们能够获取每个模块相应的配置数据。

疑惑:conf_ctx指向的是内存池的一块空间,保存着各个模块的相关配置信息,不过它是个 四级指针,这个怎么变成数组来应用了呢?

NGX_CORE_MODULE类型的模块有:ngx_core_module、ngx_errlog_module、ngx_events_module和ngx_http_module等。

ngx_core_module定义在src/core/nginx.c文件中,create_conf钩子对应的函数为ngx_core_module_create_conf(),此函数就是创建ngx_core_conf_t配置结构。

ngx_errlog_module定义在src/core/ngx_log.c中,create_conf钩子没有对应的回调函数,为NULL。

ngx_events_module定义在src/event/ngx_event.c中,create_conf钩子没有对应的回调函数,为NULL。

ngx_http_module定义在src/http/ngx_http.c中,create_conf钩子没有对应的回调函数,为NULL。

由此可以看出,此处的循环执行create_conf回调函数,其实就只调用了ngx_core_module_create_conf()。

 

 261     if (ngx_conf_param(&conf) != NGX_CONF_OK) {

 262         environ = senv;

 263         ngx_destroy_cycle_pools(&conf);

 264         return NULL;

 265     }

 266    

 267     if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {

 268         environ = senv;

 269         ngx_destroy_cycle_pools(&conf);

 270         return NULL;

 271     }

这里将完成对配置文件的解析工作,做过Nginx模块开发的都清楚——解析配置文件的时候,将会完成每个指令的set回调,这个set回调函数一般都是用于将配置数据填写到配置结构中。 解析配置文件常用的手法之一就是利用状态机,但此处Nginx却没有明确的使用状态机来完成配置文件的解析工作。

后经仔细阅读代码,只有配置模块的type符合NGX_CONF_MODULE,会调用set回调。代码在ngx_config_file.c ,如下

 

 292     for (i = 0; ngx_modules[i]; i++) {                                                 

 293                                                                                            

 294                                      

 295                                                  

 296         if (ngx_modules[i]->type != NGX_CONF_MODULE                                        

 297             && ngx_modules[i]->type != cf->module_type)                                    

 298         {  

 299             continue;                                                                      

 300         }                                                              

 302         cmd = ngx_modules[i]->commands;  

             。 。 。

393             rv = cmd->set(cf, cmd, conf);

 

其中set回调在定义ngx_conf_commands时赋值为ngx_conf_include,代码见ngx_config_file.c:23。ngx_conf_include函数的作用以后再详细查看。

还有就是核心模块的set回调,见如下代码nginx.c:32

  static ngx_command_t  ngx_core_commands[] = {

 

    { ngx_string("daemon"),

      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,

      ngx_conf_set_flag_slot,     //set回调函数

      0,

      offsetof(ngx_core_conf_t, daemon),

      NULL },

 

    { ngx_string("master_process"),

      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,

      ngx_conf_set_flag_slot,     //set回调函数

      0,

      offsetof(ngx_core_conf_t, master),

      NULL },

       . . .

     }

 

以上作用都是将配置信息解析出来,放在提前分配好的内存空间,之后可以随时访问这些配置信息。

 

 278     for (i = 0; ngx_modules[i]; i++) {

 279         if (ngx_modules[i]->type != NGX_CORE_MODULE) {

 280             continue;

 281         }

 282

 283         module = ngx_modules[i]->ctx;

 284

 285         if (module->init_conf) {

 286             if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])

 287                 == NGX_CONF_ERROR)

 288             {

 289                 environ = senv;

 290                 ngx_destroy_cycle_pools(&conf);

 291                 return NULL;

 292             }

 293         }

 294     }

前面完成了NGX_CORE_MODULE类型模块的配置结构创建工作,这里调用所有NGX_CORE_MODULE类型模块的init_conf回调函数,完成配置结构的初始化工作。同ceate_conf,其实此处也只是调用了ngx_core_module的ngx_core_module_init_conf()回调函数。对ceate_conf创建的配置结构进行初始化。其他几个NGX_CORE_MODULE没有init_conf回调函数。

 

597     for (i = 0; ngx_modules[i]; i++) {                  

 598         if (ngx_modules[i]->init_module) {

 599             if (ngx_modules[i]->init_module(cycle) != NGX_OK) {

 600                   

 601                 exit(1);

 602             }

 603         }

 604     }

执行所有模块的init_module操作,看名字为对模块进行初始化。 浏览源码,发现包括几个NGX_CORE_MODULE类型的模块在内的绝大多数模块都没有这个init回调函数。究竟哪些模块才使用这个回调接口呢?动用搜索功能,终于找到了一个模块使用了这个回调接口,它就是ngx_event_core_module。在此,就不纠结这个独特的初始化函数了,到分析事件驱动的时候,再回头看看。 

http://blog.sina.com.cn/s/blog_8755c64501011jdf.html

http://www.linuxidc.com/Linux/2011-05/35348.htm

http://www.cnblogs.com/luhouxiang/archive/2012/09/19/2693632.html

http://www.cnblogs.com/luhouxiang/archive/2012/09/18/2690161.html

转载于:https://my.oschina.net/mickelfeng/blog/98616

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值