文章1:Nginx源码分析—main函数

本章先分析Nginx启动过程中main函数依次调用的各个子函数,分析完main中的所有子函数后,然后在文章前面总结完整的main()代码以及nginx启动流程。

/*
函数名:ngx_get_options
功能:根据命令行参数,将对应标志位置位;将输入的命令行参数(字符串地址)保存到对应的全局变量中。
参数:argc,argv
*/
static ngx_int_t
ngx_get_options(int argc, char *const *argv)
{
    u_char     *p;
    ngx_int_t   i;
 
    for (i = 1; i < argc; i++) {
        p = (u_char *) argv[i];
 
        if (*p++ != '-') {
            ngx_log_stderr(0, "invalid option: \"%s\"", argv[i]);
            return NGX_ERROR;
        }
 
        while (*p) {
 
            switch (*p++) {
 
            case '?':
            case 'h':
                ngx_show_version = 1;
                ngx_show_help = 1;
                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;
 
            // 使用-q参数可以不把error级别以下的信息输出到目录
            case 'q':
                ngx_quiet_mode = 1;
                break;
 
            /* -p参数指定nginx的安装目录来启动nginx,例如:/usr/local/nginx/sbin/nginx  -p  /usr/local/nginx */
            case 'p':
 
                /* 如果-p后面接的参数与-p之间没有空格,如:nginx  -p/usr/local/nginx/,p指向/usr/local/nginx/ */
                if (*p) {
                    //全局变量ngx_prefix指向字符串/usr/local/nginx/
                    ngx_prefix = p;
                    //跳出while循环,解析下一个命令行参数。
                    goto next;
                }
 
                /* 若-p与后面的参数有空格,比如:nginx  –p  /usr/local/nginx/,argv[++i]指向/usr/local/nginx/ */
                if (argv[++i]) {
                    ngx_prefix = (u_char *) argv[i];
                    goto next;
                }
 
                ngx_log_stderr(0, "option \"-p\" requires directory name");
                return NGX_ERROR;
 
            /*使用-c参数指定配置文件来启动nginx,例如:
/usr/local/nginx/sbin/nginx  -c  /tmp/nginx.conf  */
            case 'c':
                /* 如果-c后面接的参数与-c之间没有空格,如:nginx  -c/tmp/nginx.conf,p指向/tmp/nginx.conf。*/
                if (*p) {
                    // ngx_conf_file指向/tmp/nginx.conf。
                    ngx_conf_file = p;
                    goto next;
                }
 
                /*如果-c与后面的参数有空格,如:nginx  -c  /tmp/nginx.conf,argv[++i]指向字符串/tmp/nginx.conf的地址 */
                if (argv[++i]) {
                    ngx_conf_file = (u_char *) argv[i];
                    goto next;
                }
 
                ngx_log_stderr(0, "option \"-c\" requires file name");
                return NGX_ERROR;
 
            // 使用-g参数临时指定一些全局配置项,以使新的配置项生效。
            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;
 
            // -s是告诉nginx程序向正在运行的nginx服务发出信号量。
            case 's':
                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;
                }
                /* stop:强行停止,quit:优雅停止,reopen:回滚日志文件,reload:重载配置文件 */
                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;
            }
        }
 
    // 跳出while循环
    next:
 
        continue;
    }
 
return NGX_OK;
}
 
 
/*初始化并更新时间 */
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_time = &cached_time[0];
 
    /* 初始化全局变量ngx_cached_time,ngx_cached_http_time.data,ngx_cached_http_log_time.data,ngx_cached_http_log_time.data */
    ngx_time_update();
}
 
/* 
函数名:ngx_log_init
功能:初始化全局变量ngx_log,创建或打开日志文件ngx_log_file.fd
参数prefix:main函数调用传递的实参为ngx_prefix,即Nginx的安装路径
*/
//下面是与该函数相关的一些全局变量的定义
struct ngx_log_s {
ngx_unit_t     log_level;
ngx_open_file_t    *file;
ngx_atomic_unit_t  connection;
ngx_log_handler_pt handler;
void     *data;
char   *action;
}
 
struct ngx_open_file_s {
   ngx_fd_t              fd;
   ngx_str_t             name;
 
   u_char               *buffer;
   u_char               *pos;
   u_char               *last;
 
#if 0
   /* e.g. append mode, error_log */
   ngx_uint_t            flags;
   /* e.g. reopen db file */
   ngx_uint_t         (*handler)(void *data, ngx_open_file_t *file);
   void                 *data;
#endif
}
 
static ngx_log_t        ngx_log;
static ngx_open_file_t  ngx_log_file;
 
ngx_log_t *
ngx_log_init(u_char *prefix)
{
   u_char  *p, *name;
   size_t   nlen, plen;
 
   ngx_log.file = &ngx_log_file;
   ngx_log.log_level = NGX_LOG_NOTICE;
 
    // 默认值“logs/error.log“
   name = (u_char *) NGX_ERROR_LOG_PATH;
 
   /*
    * we use ngx_strlen() here since BCC warns about
    * condition is always false and unreachable code
    */
 
   nlen = ngx_strlen(name);
 
    if (nlen == 0) {
       ngx_log_file.fd = ngx_stderr;
       return &ngx_log;
    }
 
    p= NULL;
 
#if (NGX_WIN32)
   if (name[1] != ':') {
#else
   if (name[0] != '/') {
#endif
 
       if (prefix) {
           plen = ngx_strlen(prefix);
 
       } else {
#ifdef NGX_PREFIX
           /* 若prefix为0,且定义了默认路径,则使用默认的安装路径NGX_PREFIX,默认"/usr/local/nginx/" */
           prefix = (u_char *) NGX_PREFIX;
           plen = ngx_strlen(prefix);
#else
           plen = 0;
#endif
       }
 
       if (plen) {
           // 分配长度为 /usr/local/nginx/ + logs/error.log
           name = malloc(plen + nlen + 2);
           if (name == NULL) {
                return NULL;
           }
           // 复制路径如/usr/local/nginx/,到name所指的存储区域
           p = ngx_cpymem(name, prefix, plen);
 
           // 若上条语句复制的prefix不是以”/”结尾,则在后面加上”/”
           if (!ngx_path_separator(*(p - 1))) {
                *p++ = '/';
           }
 
           /* 以尾部添加的方式复制 NGX_ERROR_LOG_PATH到name,此时name所指的字符串为prefix + NGX_ERROR_LOG_PATH,如/usr/local/nginx/ logs/error.log */
           ngx_cpystrn(p, (u_char *) NGX_ERROR_LOG_PATH, nlen + 1);
 
           //使p指向字符串首
           p = name;
       }
    }
 
    // 创建或打开name文件
   ngx_log_file.fd = ngx_open_file(name, NGX_FILE_APPEND,
                                   NGX_FILE_CREATE_OR_OPEN,
                                    NGX_FILE_DEFAULT_ACCESS);
 
   if (ngx_log_file.fd == NGX_INVALID_FILE) {
       ngx_log_stderr(ngx_errno,
                       "[alert] could notopen error log file: "
                       ngx_open_file_n "\"%s\" failed", name);
#if (NGX_WIN32)
       ngx_event_log(ngx_errno,
                       "could not openerror log file: "
                       ngx_open_file_n "\"%s\" failed", name);
#endif
 
       ngx_log_file.fd = ngx_stderr;
    }
 
    // 释放p指向的内存
   if (p) {
       ngx_free(p);
    }
 
   return &ngx_log;
}


/* 函数名:ngx_process_options
   参数:main函数调用时传递的init_cycle的地址
   功能:初始化cycle结构体中的prefix,conf_prefix,conf_file等变量
*/
  
static ngx_int_t
ngx_process_options(ngx_cycle_t *cycle)
{
   u_char  *p;
   size_t   len;
 
    // 如果ngx_prefix已被初始化且不为0
   if (ngx_prefix) {
       len = ngx_strlen(ngx_prefix);
       p = ngx_prefix;
       
       /* 若p指向的内容不是以‘/’开头,则为它分配内存,将ngx_prefix的内容复制过去 */
       if (!ngx_path_separator(*p)) {
           p = ngx_pnalloc(cycle->pool, len + 1);
           if (p == NULL) {
                return NGX_ERROR;
           }
 
           ngx_memcpy(p, ngx_prefix, len);
           // p指向的内容以‘/’结尾
           p[len++] = '/';
       }
       // conf_prefix为Nginx配置文件所在目录的路径,这里对其进行初始化
       cycle->conf_prefix.len = len;
       cycle->conf_prefix.data = p;
       // prefix为Nginx安装目录的路径
       cycle->prefix.len = len;
       cycle->prefix.data = p;
 
    }else {
// 若没有初始化ngx_prefix,且自动生成的配置文件中也没有定义NGX_PREFIX
#ifndef NGX_PREFIX
 
       p = ngx_pnalloc(cycle->pool, NGX_MAX_PATH);
       if (p == NULL) {
           return NGX_ERROR;
       }
 
       // 获取当前工作目录,将其绝对地址保存在p中
       if (ngx_getcwd(p, NGX_MAX_PATH) == 0) {
           ngx_log_stderr(ngx_errno, "[emerg]: " ngx_getcwd_n "failed");
           return NGX_ERROR;
       }
 
       len = ngx_strlen(p);
 
       p[len++] = '/';
 
       cycle->conf_prefix.len = len;
       cycle->conf_prefix.data = p;
       cycle->prefix.len = len;
       cycle->prefix.data = p;
 
// 若定义了NGX_PREFIX
#else
 
// 若定义NGX_CONF_PREFIX
#ifdef NGX_CONF_PREFIX
       ngx_str_set(&cycle->conf_prefix, NGX_CONF_PREFIX);
#else
       ngx_str_set(&cycle->conf_prefix, NGX_PREFIX);
#endif
       ngx_str_set(&cycle->prefix, NGX_PREFIX);
 
#endif
    }
 
    /* 若已初始化ngx_conf_file(配置文件相对于安装目录的路径),对cycle的conf_file成员初始化 */
   if (ngx_conf_file) {
       cycle->conf_file.len = ngx_strlen(ngx_conf_file);
       cycle->conf_file.data = ngx_conf_file;
 
} else {
    /* 若没有初始化ngx_conf_file,则使用自动生成的配置文件中定义的宏,如:“conf/nginx.conf”*/
       ngx_str_set(&cycle->conf_file, NGX_CONF_PATH);
    }
    // 将获得配置文件的绝对路径,并保存到cycle->conf_file,为什么要执行这步操作?
   if (ngx_conf_full_name(cycle, &cycle->conf_file, 0) != NGX_OK) {
       return NGX_ERROR;
    }
 
   for (p = cycle->conf_file.data + cycle->conf_file.len - 1;
        p > cycle->conf_file.data;
        p--)
{
    /* p指针由字符串尾向头部移动,遇到第一个‘/’,执行下面操作,实际是去掉配置文件名,conf.prefix只保存配置文件的目录 */
       if (ngx_path_separator(*p)) {
           cycle->conf_prefix.len = p - ngx_cycle->conf_file.data + 1;
           cycle->conf_prefix.data = ngx_cycle->conf_file.data;
           break;
       }
    }
 
// Nginx处理配置文件时需要特殊处理的在配置行携带的参数
   if (ngx_conf_params) {
       cycle->conf_param.len = ngx_strlen(ngx_conf_params);
       cycle->conf_param.data = ngx_conf_params;
    }
 
   if (ngx_test_config) {
       cycle->log->log_level = NGX_LOG_INFO;
    }
 
   return NGX_OK;
}

下面这段代码是main()中初始化每个module的index,index的值是按ngx_modules.c中模块的定义顺序来初始化的。编译nginx后,会在源代码根生成objs目录,该目录中包含ngx_auto_config.h,ngx_auto_headers.h,ngx_modules.c,makefile。

    // ngx_max_module表示nginx一共有的模块个数。
    ngx_max_module = 0;
    for (i = 0; ngx_modules[i]; i++) {
        ngx_modules[i]->index = ngx_max_module++;
    }



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值