1、以下是我阅读nginx(1.13.2版本)源码的一些心得,个人觉得学一个东西最好学它的思想,学会举一反三。因为互联网的东西实在太多 了。
上一章我对nginx启动流程做了一个大概的描述,这一张我详细进入初始化的核心方法进行探索。文章尾部会附上一张nginx中核心结构体
nginx_cycle_s的图,方便在阅读源代码的时候进行对比和理解。
函数名称:
ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle)
//第一步:声明这些变量,变量的意义在初始化的时候进行说明
void *rv;
char **senv;
ngx_uint_t i, n;
ngx_log_t *log;
ngx_time_t *tp;
ngx_conf_t conf;
ngx_pool_t *pool;
ngx_cycle_t *cycle, **old;
ngx_shm_zone_t *shm_zone, *oshm_zone;
ngx_list_part_t *part, *opart;
ngx_open_file_t *file;
ngx_listening_t *ls, *nls;
ngx_core_conf_t *ccf, *old_ccf;
ngx_core_module_t *module;
char hostname[NGX_MAXHOSTNAMELEN];
//第二步:开始初始化这些变量把指针赋值给cycle结构体
ngx_timezone_update();
ngx_time_update(); //调用ngx_timezone_update()更新时区,调用ngx_time_update()更新时间
pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);//申请一个空间内存池,NGX_CYCLE_POOL_SIZE的值为16*1024
cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));//从内存池中申请内存存放cycle结构体,这个是核心的结构体
//这些已经在main函数中获取到的值直接赋值给新的核心结构体cycle,不需要再次去解析
cycle->pool = pool;
cycle->log = log;
cycle->old_cycle = old_cycle;
cycle->conf_prefix.len = old_cycle->conf_prefix.len;
cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
cycle->prefix.len = old_cycle->prefix.len;
cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix);
cycle->conf_file.len = old_cycle->conf_file.len;
cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1);
cycle->conf_param.len = old_cycle->conf_param.len;
cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *);//初始化一个大小为n,可动态扩展的数组,cycle的paths用来存储的是路径,比如配置很多配置文件的路径
ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t);
ngx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel, ngx_str_rbtree_insert_value);//红黑树,平衡二叉树一种,用来坐二分搜索用的
ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t); //打开文件的list,具体list结构参考:http://blog.csdn.net/chen19870707/article/details/40400719
ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t);//共享内存的初始化
ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t);//连接监听的数组,具体结构附录图
ngx_queue_init(&cycle->reusable_connections_queue);//队列初始化,这个结构体比较简单就两个属性, prev,next
cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));//给每个模块都分配一个配置属性指针,后面nginx.conf以及其他配置文件中的配置会放到这里
第三步:for循环初始化核心的module,读取配置文件,给cycle中已经初始化了的变量进行赋值。
1、函数名称:
ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle){
cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1) * sizeof(ngx_module_t *));//申请内存空间,存放module的结构体
ngx_memcpy(cycle->modules, ngx_modules, ngx_modules_n * sizeof(ngx_module_t *));//把全局静态变量的内存信息拷贝过来,这个ngx_modules是在编译的时候确定好的,即你安装的时候指定需要使用的扩展,具体可以查看上一章的内容
cycle->modules_n = ngx_modules_n; //赋值扩展的数量
}
2、核心模块配置信息预处理:
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->type != NGX_CORE_MODULE) {//非核心模块不处理
continue;
}
module = cycle->modules[i]->ctx; //模块的上下文
if (module->create_conf) {
rv = module->create_conf(cycle);
if (rv == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->conf_ctx[cycle->modules[i]->index] = rv;
}
}
conf.ctx = cycle->conf_ctx;
conf.cycle = cycle;
conf.pool = pool;
conf.log = log;
conf.module_type = NGX_CORE_MODULE;
conf.cmd_type = NGX_MAIN_CONF;
3、准备了这些之后就可以解析配置文件了:
第一个if解析nginx命令行参数’-g’加入的配置。第二个if解析nginx配置文件。好的设计就体现在接口极度简化,模块之间的耦合非常低。这里只使用区区10行完成了配置的解析。在这里,我们先浅尝辄止,具体nginx如何解析配置,我们将在后面的小节做细致的介绍。-g是指在命令行加入临时的配置信息,下一章直接解析ngx_conf_parse的详细实现,分析是如何对配置文件进行解析的。
附图(从网上找的,自己画太麻烦):