nginx源码分析—启动流程

0. 序
1. main()分析
2. 注意问题
2.1 几个初值
2.2 nginx工作模式
2.3 一些配置
2.4 其他开关
3. 小结

0. 

本文主要分析nginx主程序。

nginx主程序main()实现文件:./src/core/nginx.c.表示nginx-1.0.4代码目录,本文为/usr/src/nginx-1.0.4

1. main()分析

nginx启动过程如下。

  • 调用ngx_get_options()解析命令参数;
  • 调用ngx_time_init()初始化并更新时间,如全局变量ngx_cached_time
  • 调用ngx_log_init()初始化日志,如初始化全局变量ngx_prefix,打开日志文件ngx_log_file.fd
  • 清零全局变量ngx_cycle,并为ngx_cycle.pool创建大小为1024B的内存池;
  • 调用ngx_save_argv()保存命令行参数至全局变量ngx_os_argvngx_argcngx_argv中;
  • 调用ngx_process_options()初始化ngx_cycleprefix, conf_prefix, conf_file, conf_param等字段;
  • 调用ngx_os_init()初始化系统相关变量,如内存页面大小ngx_pagesize,ngx_cacheline_size,最大连接数ngx_max_sockets等;
  • 调用ngx_crc32_table_init()初始化CRC(后续的CRC校验通过查表进行,效率高)
  • 调用ngx_add_inherited_sockets()继承sockets
    • 解析环境变量NGINX_VAR="NGINX"中的sockets,并保存至ngx_cycle.listening数组;
    • 设置ngx_inherited=1
    • 调用ngx_set_inherited_sockets()逐一对ngx_cycle.listening数组中的sockets进行设置;
    • 具体可参考<nginx源码分析—初始化过程中处理继承的sockets>
  • 初始化每个moduleindex,并计算ngx_max_module;具体可参考<nginx源码分析—模块及其初始化>
  • 调用ngx_init_cycle()进行初始化;
    • 该初始化主要对ngx_cycle结构进行;
    • 具体可参考<nginx源码分析—全局变量ngx_cycle的初始化>
  • 若有信号,则进入ngx_signal_process()处理;
  • 调用ngx_init_signals()初始化信号;主要完成信号处理程序的注册;
  • 若无继承sockets,且设置了守护进程标识,则调用ngx_daemon()创建守护进程;
  • 调用ngx_create_pidfile()创建进程记录文件;(NGX_PROCESS_MASTER=1进程,不创建该文件)
  • 进入进程主循环;
    • 若为NGX_PROCESS_SINGLE=1模式,则调用ngx_single_process_cycle()进入进程循环;
    • 否则为master-worker模式,调用ngx_master_process_cycle()进入进程循环;
    • 具体可参考<nginx源码分析—master/worker进程启动>

 

简要的函数调用图如下。具体的还是需要阅读源代码。图的自动生成,可参考<Graphviz可视化函数调用-使用开源软件来简化复杂调用结构>


2. 注意问题
2.1 几个初值 

[cpp]  view plain copy
  1. 00353:    ngx_cycle = cycle;  /* cycle是调用ngx_init_cycle()的返回值,而调用该函数的参数也是ngx_cycle */  
  2. 00354:  
  3. 00355:    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);  
  4. 00356:  
  5. 00357:    if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) { /* ccf->master=-1 */  
  6. 00358:        ngx_process = NGX_PROCESS_MASTER;  
  7. 00359:    }  
此处单独将该段代码拿出来,说明以下问题。

ngx_process在此处的值是什么?——NGX_PROCESS_SINGLE=0

ccf->master在此处的值之什么?——NGX_CONF_UNSET=-1

ngx_prefix何时初始化的?——ngx_log_init()中初始化

(1)ccf->master

ccf->master的值是在ngx_init_cycle()函数中调用NGX_CORE_MODULE模块的create_conf钩子(callback)完成初始化的。

具体可参考<nginx源码分析—core模块callback>。

(2)ngx_process

ngx_process是全局变量,定义如下。

[cpp]  view plain copy
  1. //./src/os/unix/ngx_process_cycle.c  
  2. ngx_uint_t    ngx_process;  
  3. ngx_pid_t     ngx_pid;  
  4. ngx_uint_t    ngx_threaded;  

其在ngx_init_cycle()中没有被初始化,故其初值为0。

(3)ngx_prefix

[cpp]  view plain copy
  1. static u_char      *ngx_prefix;       /* nginx工作目录,默认为/usr/local/nginx/ */  
  2. static u_char      *ngx_conf_file;    /* 配置文件 */  
  3. static u_char      *ngx_conf_params;  /* nginx指令 */  
在ngx_log_init()中初始化。

实际上,在main()函数开始调用的ngx_get_options()函数,即是处理nginx启动的命令,并从中获取参数并赋予相应的变量。

-p:ngx_prefix

-c:ngx_conf_file

-g:ngx_conf_params

-s:ngx_signal

关于这一点,可从以下命令结果看出端倪。

[plain]  view plain copy
  1. # ./nginx -h  
  2. nginx: nginx version: nginx/1.0.4  
  3. nginx: Usage: nginx [-?hvVtq] [-s signal] [-c filename] [-p prefix] [-g directives]  
  4.   
  5. Options:  
  6.   -?,-h         : this help  
  7.   -v            : show version and exit  
  8.   -V            : show version and configure options then exit  
  9.   -t            : test configuration and exit  
  10.   -q            : suppress non-error messages during configuration testing  
  11.   -s signal     : send signal to a master process: stop, quit, reopen, reload  
  12.   -p prefix     : set prefix path (default: /usr/local/nginx/)  
  13.   -c filename   : set configuration file (default: conf/nginx.conf)  
  14.   -g directives : set global directives out of configuration file  

2.2 nginx工作模式

因此,main()函数返回前调用ngx_master_process_cycle()函数进入多进程(master/worker)工作模式。如下。

[cpp]  view plain copy
  1. 00401:    if (ngx_process == NGX_PROCESS_SINGLE) {  /* 单进程 */  
  2. 00402:        ngx_single_process_cycle(cycle);  
  3. 00403:  
  4. 00404:    } else {                                  /* 多进程 */  
  5. 00405:        ngx_master_process_cycle(cycle);  
  6. 00406:    }  
具体请参考<nginx源码分析—master/worker进程启动>。

2.3 一些配置

看源代码时,会注意到有些宏(宏全部大写,中间用下划线隔开,这是nginx代码规范。实际上,绝大多数系统均采用此规范)找不到定义,例如NGX_PREFIX、NGX_CONF_PREFIX、NGX_CONF_PATH等。

实际上,这些宏定义由configure程序进行自动配置时生成。配置时会自动生成ngx_auto_config.h文件(如果你用source insight阅读源代码,需要将该文件加入工程),如下。

./objs/ngx_auto_config.h(此处列出其中一部分常用的宏,未按顺序)

[cpp]  view plain copy
  1. #ifndef NGX_COMPILER  
  2. #define NGX_COMPILER  "gcc 4.6.1 20110908 (Red Hat 4.6.1-9) (GCC) "  
  3. #endif  
  4.   
  5. #ifndef NGX_PCRE  
  6. #define NGX_PCRE  1  
  7. #endif  
  8.   
  9. #ifndef NGX_PREFIX  
  10. #define NGX_PREFIX  "/usr/local/nginx/"  
  11. #endif  
  12.   
  13. #ifndef NGX_CONF_PREFIX  
  14. #define NGX_CONF_PREFIX  "conf/"  
  15. #endif  
  16.   
  17. #ifndef NGX_CONF_PATH  
  18. #define NGX_CONF_PATH  "conf/nginx.conf"  
  19. #endif  
  20.   
  21. #ifndef NGX_PID_PATH  
  22. #define NGX_PID_PATH  "logs/nginx.pid"  
  23. #endif  
  24.   
  25. #ifndef NGX_LOCK_PATH  
  26. #define NGX_LOCK_PATH  "logs/nginx.lock"  
  27.   
  28. #ifndef NGX_ERROR_LOG_PATH  
  29. #define NGX_ERROR_LOG_PATH  "logs/error.log"  
  30. #endif  
  31.   
  32. #ifndef NGX_HTTP_LOG_PATH  
  33. #define NGX_HTTP_LOG_PATH  "logs/access.log"  
  34. #endif  
  35.   
  36. #ifndef NGX_HTTP_CLIENT_TEMP_PATH  
  37. #define NGX_HTTP_CLIENT_TEMP_PATH  "client_body_temp"  
  38. #endif  
  39.   
  40. #ifndef NGX_HTTP_PROXY_TEMP_PATH  
  41. #define NGX_HTTP_PROXY_TEMP_PATH  "proxy_temp"  
  42. #endif  

2.4 其他开关

还有一些开关,如NGX_FREEBSD, NGX_PCRE,NGX_OPENSSL等,这些宏也在configure过程中自动配置。nginx启动时会根据这些宏是否定义调用相应的函数。此处非本文重点,不再赘述。

以上3个宏分别调用相应函数进行debug的初始化、正则表达式初始化和SSL的初始化。如下。(代码未按顺序)

[cpp]  view plain copy
  1. #if (NGX_FREEBSD)  
  2.     ngx_debug_init();  
  3. #endif  
  4.   
  5. #if (NGX_PCRE)  
  6.     ngx_regex_init();  
  7. #endif  
  8.   
  9. #if (NGX_OPENSSL)  
  10.     ngx_ssl_init(log);  
  11.   
  12. #endif  

3. 小结

本文简单分析nginx的启动过程,后文继续分析其中的ngx_init_cycle()和master/worker工作模型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值