在這一節終於可以開始看流程看機制了,還是小激動的,畢竟只看數據結構還是不懂。因爲數據結構+算法+代碼才能完整的理解nginx啊。前面11節我們總結了所有可能用到的基本數據結構,至於每個結構相應的方法,出了str其他沒有過多講述,後面看流程的時候遇到都會進行研究。
我就直接分階段貼代碼了,一段一段慢慢的看。有一些內容對理解沒什麼用就直接…了,見諒。
Block 1: 初始化基礎模塊
—->>函數啓動:main
int ngx_cdecl // 在第1節裏有,ngx_cdecl是一個留用的宏定義,爲了解決以後可能出現的移植性問題
main(int argc, char *const *argv)
{
ngx_int_t i; // 後面都用來做循環的index
ngx_log_t *log;
ngx_cycle_t *cycle, init_cycle;
ngx_core_conf_t *ccf;
ngx_debug_init(); // 根據NGX_DEBUG_MALLOC來設定ngx_debug_malloc參數
—->>函數調用:ngx_debug_init
void ngx_debug_init(void)
{
#if (NGX_DEBUG_MALLOC)
// 改變或新增加環境變量(注意這裏的環境變量是當前進程的,和shell無關,進程結束就沒了)
setenv("MallocScribble", "1", 0);
ngx_debug_malloc = 1;
#else
// 沒有定義,看系統中是否有定義MallocScribble,有的話設置ngx_debug_malloc
if (getenv("MallocScribble")) {
ngx_debug_malloc = 1;
}
#endif
}
<<—-調用返回:main
// 初始化errlist列表
if (ngx_strerror_init() != NGX_OK) {
return 1;
}
—->>函數調用:ngx_strerror_init
ngx_int_t ngx_strerror_init(void)
{
char *msg; // 臨時使用的指針,接收strerror返回的字符串
u_char *p; // 臨時使用的指針,創建內存後獲取內容並轉交地址
size_t len; // 臨時使用的長度
ngx_err_t err; // 錯誤代碼
/* 申請內存空間給errlist,NGX_SYS_NERR是錯誤熟料 */
len = NGX_SYS_NERR * sizeof(ngx_str_t);
ngx_sys_errlist = malloc(len); // ngx_errno.c定義的靜態指針
if (ngx_sys_errlist == NULL) {
goto failed;
// 問:這裏爲什麼使用goto不用if-else?看起來用else也不會讓邏輯混亂啊。
// 答:不覺得goto很方便麼,多個else放一個goto裏處理。反正在功能性函數內不會亂。
}
/* 使用標準庫函數strerror根據錯誤代碼返回錯誤原因的描述字符串,並存儲到errlist中 */
for (err = 0; err < NGX_SYS_NERR; err++) {
msg = strerror(err);
len = ngx_strlen(msg);
p = malloc(len);
if (p == NULL) {
goto failed;
}
ngx_memcpy(p, msg, len);
ngx_sys_errlist[err].len = len;
ngx_sys_errlist[err].data = p;
}
return NGX_OK;
/* malloc錯誤統一處理,因爲這時errlist還沒初始化好,ngx_strerror不能用,所以使用log_error */
failed:
err = errno;
ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err));
return NGX_ERROR;
}
<<—-調用返回:main
Block 2: 獲取參數
/* 解析命令行輸入的各參數 */
if (ngx_get_options(argc, argv) != NGX_OK) {
return 1;
}
—->>函數調用:ngx_get_options
static ngx_int_t ngx_get_options(int argc, char *const *argv)
{
u_char *p;
ngx_int_t i;
/* 循環解析參數,跟之前一篇博文使用標準解析函數的方法不一樣,這樣解析更加靈活
* argv[0]是程序執行路徑,不解析 */
for (i = 1; i < argc; i++) {
/* 指針位置就是p[0]位置,直接解析字符,如果不是-說明參數格式錯誤 */
p = (u_char *) argv[i];
if (*p++ != '-') {
ngx_log_stderr(0, "invalid option: \"%s\"", argv[i]);
return NGX_ERROR;
}
/* 發現'-'後p++已經指向對應的參數(加減單位是sizeof(u_char)),進行解析設置相應參數 */
while (*p) {
switch (*p++) {
case '?':
case 'h':
ngx_show_version = 1; // 用於顯示version信息
ngx_show_help = 1; // 用於顯示help信息
break;
case 'v':
ngx_show_version = 1;
break;
case 'V':
ngx_show_version = 1;
ngx_show_configure = 1; // 用於顯示配置信息
break;
case 't':
ngx_test_config = 1; // 檢測配置文件
break;
case 'q':
ngx_quiet_mode = 1; // -t的參數
break;
case 'p': // 設置prefix路徑
if (*p) {
ngx_prefix = p;
goto next;
}
if (argv[++i]) {
ngx_prefix = (u_char *) argv[i];
goto next;
}
ngx_log_stderr(0, "option \"-p\" requires directory name");
return NGX_ERROR;
case 'c': // 設置配置文件
/* 參數直接跟在p後面"-p/home/tut/..." */
if (*p) {
ngx_conf_file = p;
goto next;
}
/* 參數在下一個argv */
if (argv[++i]) {
ngx_conf_file = (u_char *) argv[i];
goto next;
}
ngx_log_stderr(0, "option \"-c\" requires file name");
return NGX_ERROR;
case 'g':
if (*p) {
ngx_conf_params = p; // 全局配置文件輸出文件夾
goto next;
}
if (argv[++i]) {
ngx_conf_params = (u_char *) argv[i];
goto next;
}
ngx_log_stderr(0, "option \"-g\" requires parameter");
return NGX_ERROR;
case 's':
/* 在沒錯的情況下有後續操作,所以沒用goto用了if-else */
if (*p) {
ngx_signal = (char *) p;
} else if (argv[++i]) {
ngx_signal = argv[i];
} else {
ngx_log_stderr(0, "option \"-s\" requires parameter");
return NGX_ERROR;
}
/* 這幾種信號都在signaller進程中處理了到時候,其他信號不處理 */
if (ngx_strcmp(ngx_signal, "stop") == 0
|| ngx_strcmp(ngx_signal, "quit") == 0
|| ngx_strcmp(ngx_signal, "reopen") == 0
|| ngx_strcmp(ngx_signal, "reload") == 0)
{
ngx_process = NGX_PROCESS_SIGNALLER;
goto next;
}
ngx_log_stderr(0, "invalid option: \"-s %s\"", ngx_signal);
return NGX_ERROR;
default:
ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1));
return NGX_ERROR;
}
}
next:
continue;
}
return NGX_OK;
}
—-<<調用返回:main
if (ngx_show_version) {
/* ngx_write_stderr -> ngx_write_fd(ngx_stderr(宏定義標準錯誤輸出),...) -> write(fd,...) */
ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED);
if (ngx_show_help) {
ngx_write_stderr("輸出使用說明,篇幅太長,省略,感興趣的直接源碼或者-h");
}
if (ngx_show_configure) {/* 輸出各種配置信息 */}
if (!ngx_test_config) { // 沒啥事了(不需要檢測config),可以退出了
return 0;
}
}
Block 1:初始化基礎模塊
/* TODO */ ngx_max_sockets = -1;
ngx_time_init(); // 初始化系統時間
—->>函數調用:ngx_time_init
void ngx_time_init(void)
{
ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1;
ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1;
ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1;
/* static ngx_time_t cached_time[NGX_TIME_SLOTS];*/
ngx_cached_time = &cached_time[0];
ngx_time_update(); // 更新系統時間
}
—->>函數調用:ngx_time_update