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

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