nginx源碼初讀(12)--跟main一起看流程(Block 1: 初始化基礎模塊 Block 2:獲取參數)

在這一節終於可以開始看流程看機制了,還是小激動的,畢竟只看數據結構還是不懂。因爲數據結構+算法+代碼才能完整的理解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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章