nginx原始碼閱讀(二).初始化:main函式及ngx_init_cycle函式
阿新 • • 發佈:2018-12-19
前言
在分析原始碼時,我們可以先把握主幹,然後其他部分再挨個分析就行了。接下來我們先看看nginx的main
函式幹了些什麼。
main函式
這裡先介紹一些下面會遇到的變數型別:
ngx_int_t
: typedef intptr_t ngx_int_t;
64位機器上,intptr_t
為long int
, 即typedef long int intptr_t;
在32位機器上,intptr_t
為int
,即typedef int intptr_t
。
ngx_log_t
: typedef struct ngx_log_s ngx_log_t
,struct ngx_log_s
儲存了日誌檔案的各種資訊
ngx_cycle_t
是很重要的結構體,等下列出它的定義。
ngx_core_conf_t
是core模組儲存配置項的結構體。
ngx_core_conf_t
是core模組儲存配置項的結構體。
/* src/core/nginx.c */ int ngx_cdecl main(int argc, char *const *argv) { ngx_int_t i; ngx_log_t *log; ngx_cycle_t *cycle, init_cycle; ngx_core_conf_t *ccf; #if (NGX_FREEBSD) ngx_debug_init(); #endif if (ngx_strerror_init() != NGX_OK) { return 1; } //處理引數,設定對應的標識位等 if (ngx_get_options(argc, argv) != NGX_OK) { return 1; } //根據標識位顯示版本、測試配置等 if (ngx_show_version) { ngx_write_stderr("nginx version: " NGINX_VER NGX_LINEFEED); if (ngx_show_help) { ngx_write_stderr( "Usage: nginx [-?hvVtq] [-s signal] [-c filename] " "[-p prefix] [-g directives]" NGX_LINEFEED NGX_LINEFEED "Options:" NGX_LINEFEED " -?,-h : this help" NGX_LINEFEED " -v : show version and exit" NGX_LINEFEED " -V : show version and configure options then exit" NGX_LINEFEED " -t : test configuration and exit" NGX_LINEFEED " -q : suppress non-error messages " "during configuration testing" NGX_LINEFEED " -s signal : send signal to a master process: " "stop, quit, reopen, reload" NGX_LINEFEED #ifdef NGX_PREFIX " -p prefix : set prefix path (default: " NGX_PREFIX ")" NGX_LINEFEED #else " -p prefix : set prefix path (default: NONE)" NGX_LINEFEED #endif " -c filename : set configuration file (default: " NGX_CONF_PATH ")" NGX_LINEFEED " -g directives : set global directives out of configuration " "file" NGX_LINEFEED NGX_LINEFEED ); } if (ngx_show_configure) { ngx_write_stderr( #ifdef NGX_COMPILER "built by " NGX_COMPILER NGX_LINEFEED #endif #if (NGX_SSL) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME "TLS SNI support enabled" NGX_LINEFEED #else "TLS SNI support disabled" NGX_LINEFEED #endif #endif "configure arguments:" NGX_CONFIGURE NGX_LINEFEED); } if (!ngx_test_config) { return 0; } } /* TODO */ ngx_max_sockets = -1; //初始化並更新時間 ngx_time_init(); #if (NGX_PCRE) ngx_regex_init(); #endif //獲取nginx的程序號 ngx_pid = ngx_getpid(); //初始化日誌 log = ngx_log_init(ngx_prefix); if (log == NULL) { return 1; } /* STUB */ #if (NGX_OPENSSL) ngx_ssl_init(log); #endif /* * init_cycle->log is required for signal handlers and * ngx_process_options() */ /* 初始化ngx_cycle * #define ngx_memzero(buf, n) (void) memset(buf, 0, n) */ ngx_memzero(&init_cycle, sizeof(ngx_cycle_t)); init_cycle.log = log; ngx_cycle = &init_cycle; //分配記憶體池 init_cycle.pool = ngx_create_pool(1024, log); if (init_cycle.pool == NULL) { return 1; } //將命令列引數儲存到init_cycle結構體中 if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) { return 1; } //用執行nginx時可能攜帶的目錄引數來初始化cycle if (ngx_process_options(&init_cycle) != NGX_OK) { return 1; } //提取當前作業系統的一些資訊 if (ngx_os_init(log) != NGX_OK) { return 1; } /* * ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init() */ //初始化一個迴圈冗餘校驗的表 //後續的迴圈冗餘校驗可以直接查表 if (ngx_crc32_table_init() != NGX_OK) { return 1; } //這個函式是為了執行不重啟服務升級nginx做準備 //通過環境變數NGINX_VAR將老的nginx程序需要監聽的埠傳給新的nginx程序,這樣就可以讀取平滑升級的資訊了 if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) { return 1; } //對所有模組進行編號 //ngx_modules陣列在編譯時已經生成了 ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; } //大部分的初始化工作都在ngx_init_cycle中進行 cycle = ngx_init_cycle(&init_cycle); if (cycle == NULL) { if (ngx_test_config) { ngx_log_stderr(0, "configuration file %s test failed", init_cycle.conf_file.data); } return 1; } if (ngx_test_config) { if (!ngx_quiet_mode) { ngx_log_stderr(0, "configuration file %s test is successful", cycle->conf_file.data); } return 0; } if (ngx_signal) { return ngx_signal_process(cycle, ngx_signal); } ngx_os_status(cycle->log); ngx_cycle = cycle; //獲取儲存ngx_core_module模組感興趣的配置項的結構體指標 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); //#define NGX_PROCESS_SINGLE 0 //#define NGX_PROCESS_MASTER 1 //#define NGX_PROCESS_SIGNALLER 2 //#define NGX_PROCESS_WORKER 3 //#define NGX_PROCESS_HELPER 4 //ccf-master若設定為on(1),並且ngx_process設定為單程序模式時 //此時由master程序設定的模式為準,為NGX_PROCESS_MASTER if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) { ngx_process = NGX_PROCESS_MASTER; } #if !(NGX_WIN32) //完成對訊號的註冊等工作 if (ngx_init_signals(cycle->log) != NGX_OK) { return 1; } //若沒有繼承sockets,並且設定了守護程序標識位 //則建立守護程序 if (!ngx_inherited && ccf->daemon) { if (ngx_daemon(cycle->log) != NGX_OK) { return 1; } ngx_daemonized = 1; } if (ngx_inherited) { ngx_daemonized = 1; } #endif //建立程序記錄檔案 if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { return 1; } if (cycle->log->file->fd != ngx_stderr) { if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_set_stderr_n " failed"); return 1; } } if (log->file->fd != ngx_stderr) { if (ngx_close_file(log->file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_close_file_n " built-in log failed"); } } ngx_use_stderr = 0; //進入程序主迴圈 //單程序方式執行nginx if (ngx_process == NGX_PROCESS_SINGLE) { ngx_single_process_cycle(cycle); } else { //以master-worker方式執行nginx ngx_master_process_cycle(cycle); } return 0; }
main
函式的程式碼邏輯大概就是這樣,下面介紹一下ngx_cycle_t
結構體,然後分析下ngx_init_cycle
函式。