• Nginx(一):启动流程解析


      nginx作为高效的http服务器和反向代理服务器,值得我们深入了解。

      我们带着几个问题,深入了解下nginx的工作原理。首先是开篇:nginx是如何启动的?

      nginx是用c写的软件,github地址: https://github.com/nginx/nginx

      其目录结构如下,我们主要关注 src 目录下的文件。

      nginx.c 是main函数入口,我们也是通过这里进行启动流程分析的。

    零、启动流程时序图

      我们先通过一个时序图进行全局观察nginx是如何跑起来的,然后后续再稍微深入了解些细节。   

      简要步骤说明:

        1. 初始化调试信息;
        2. 解析命令配置参数信息;
        3. 初始化环境信息,时间、pid、ssl...;
        4. 初始化 init_cycle 变量, 将各种配置信息放入其中;
        5. 处理继承NGINX环境变量中指定的socket;
        6. 给各处理模块编号;
        7. 初始化全局变量 ngx_cycle, 将init_cycle信息转移过来,并处理许多其他必要信息;
        8. 初始化信号控制处理器 signals;
        9. 开启worker子进程循环服务,开启master主进程循环服务;

    一、main函数启动处理实现

      通过main函数呢,也就完全理解了整个过程了,整个运行框架都在这里了。细节看需要进行深入。

    // src/core/nginx.c 入口
    int ngx_cdecl
    main(int argc, char *const *argv)
    {
        ngx_buf_t        *b;
        ngx_log_t        *log;
        ngx_uint_t        i;
        ngx_cycle_t      *cycle, init_cycle;
        ngx_conf_dump_t  *cd;
        ngx_core_conf_t  *ccf;
    
        ngx_debug_init();
        // 初始化错误信息容器
        if (ngx_strerror_init() != NGX_OK) {
            return 1;
        }
        // 解析命令行参数,有限参数
        if (ngx_get_options(argc, argv) != NGX_OK) {
            return 1;
        }
    
        if (ngx_show_version) {
            ngx_show_version_info();
    
            if (!ngx_test_config) {
                return 0;
            }
        }
    
        /* TODO */ ngx_max_sockets = -1;
    
        ngx_time_init();
    
    #if (NGX_PCRE)
        ngx_regex_init();
    #endif
    
        ngx_pid = ngx_getpid();
        ngx_parent = ngx_getppid();
        // 初始化日志文件实例
        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_memzero(&init_cycle, sizeof(ngx_cycle_t));
        init_cycle.log = log;
        // 将 ngx_cycle 和 init_cycle 指向同一块内存,以下对 init_cycle 的操作,也就是对 ngx_cycle的操作
        ngx_cycle = &init_cycle;
    
        init_cycle.pool = ngx_create_pool(1024, log);
        if (init_cycle.pool == NULL) {
            return 1;
        }
        // 保存命令行参数信息
        if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) {
            return 1;
        }
        // 设置进程相关信息,如配置文件,日志级别,配置前缀等
        if (ngx_process_options(&init_cycle) != NGX_OK) {
            return 1;
        }
        // 初始化操作系统相关的参数, 如 cpu 核数,  进程标题,页缓存大小,随机数等
        if (ngx_os_init(log) != NGX_OK) {
            return 1;
        }
    
        /*
         * ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init()
         */
        // crc32 表初始化,内存分配
        if (ngx_crc32_table_init() != NGX_OK) {
            return 1;
        }
    
        /*
         * ngx_slab_sizes_init() requires ngx_pagesize set in ngx_os_init()
         */
        // slat 大小设置初始化
        ngx_slab_sizes_init();
        // 添加继承过来的socket, 用于无中断重启
        if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
            return 1;
        }
        // 设置 ngx_module 的索引值及名称
        if (ngx_preinit_modules() != NGX_OK) {
            return 1;
        }
        // 初始化 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);
            }
    
            if (ngx_dump_config) {
                cd = cycle->config_dump.elts;
    
                for (i = 0; i < cycle->config_dump.nelts; i++) {
    
                    ngx_write_stdout("# configuration file ");
                    (void) ngx_write_fd(ngx_stdout, cd[i].name.data,
                                        cd[i].name.len);
                    ngx_write_stdout(":" NGX_LINEFEED);
    
                    b = cd[i].buffer;
    
                    (void) ngx_write_fd(ngx_stdout, b->pos, b->last - b->pos);
                    ngx_write_stdout(NGX_LINEFEED);
                }
            }
    
            return 0;
        }
        // 如果是进行启停控制,则处理信号即可
        if (ngx_signal) {
            return ngx_signal_process(cycle, ngx_signal);
        }
        // 记录操作系统信息
        // 日志级别先后: error > warn > notice > info > debug
        ngx_os_status(cycle->log);
    
        ngx_cycle = cycle;
    
        ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
    
        if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) {
            ngx_process = NGX_PROCESS_MASTER;
        }
    
    #if !(NGX_WIN32)
        // 初始化信号处理方法,针对 signals[] 中的方法进行调用注册
        if (ngx_init_signals(cycle->log) != NGX_OK) {
            return 1;
        }
    
        if (!ngx_inherited && ccf->daemon) {
            // 如果使用后台进程运行,则 fork() 当前进程后退出
            if (ngx_daemon(cycle->log) != NGX_OK) {
                return 1;
            }
    
            ngx_daemonized = 1;
        }
    
        if (ngx_inherited) {
            ngx_daemonized = 1;
        }
    
    #endif
        // 创建进程pid文件,写入 ngx_pid
        if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) {
            return 1;
        }
    
        if (ngx_log_redirect_stderr(cycle) != NGX_OK) {
            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;
    
        if (ngx_process == NGX_PROCESS_SINGLE) {
            ngx_single_process_cycle(cycle);
    
        } else {
            ngx_master_process_cycle(cycle);
        }
    
        return 0;
    }

    二、命令行参数解析

      解析命令行参数,让用户可以方便更改配置和控制nginx。没有啥复杂的,就是纯粹地按分割符将参数解析出来,放入全局的变量里,备后续的代码使用。简单看看即可。

    // 解析命令行参数, -? -h -v -V -t -T -q -p -s 
    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++) {
                // -h -v -V -t -T -q 后面无参数
                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;
    
                case 'T':
                    ngx_test_config = 1;
                    ngx_dump_config = 1;
                    break;
    
                case 'q':
                    ngx_quiet_mode = 1;
                    break;
                // -p -c -g -s  后面必带参数
                case 'p':
                    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;
                // -c 指定配置文件
                case 'c':
                    if (*p) {
                        ngx_conf_file = p;
                        goto next;
                    }
    
                    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;
                // -s 服务启停控制
                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;
                    }
    
                    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;
    }

    三、继承socket信息

      通过 NGINX 这个环境变量,可以获取到原来的nginx监听的socket信息,如果要进行优雅重启,那么把这些socket接管过来,继续处理即可实现无中断重启服务作用。

    // nginx.c, 继承之前的socket信息,无中断式重启
    static ngx_int_t
    ngx_add_inherited_sockets(ngx_cycle_t *cycle)
    {
        u_char           *p, *v, *inherited;
        ngx_int_t         s;
        ngx_listening_t  *ls;
    
        inherited = (u_char *) getenv(NGINX_VAR);
    
        if (inherited == NULL) {
            return NGX_OK;
        }
    
        ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
                      "using inherited sockets from "%s"", inherited);
    
        if (ngx_array_init(&cycle->listening, cycle->pool, 10,
                           sizeof(ngx_listening_t))
            != NGX_OK)
        {
            return NGX_ERROR;
        }
    
        for (p = inherited, v = p; *p; p++) {
            if (*p == ':' || *p == ';') {
                s = ngx_atoi(v, p - v);
                if (s == NGX_ERROR) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                                  "invalid socket number "%s" in " NGINX_VAR
                                  " environment variable, ignoring the rest"
                                  " of the variable", v);
                    break;
                }
    
                v = p + 1;
                // 添加到nginx的监听列表中
                ls = ngx_array_push(&cycle->listening);
                if (ls == NULL) {
                    return NGX_ERROR;
                }
    
                ngx_memzero(ls, sizeof(ngx_listening_t));
    
                ls->fd = (ngx_socket_t) s;
            }
        }
    
        if (v != p) {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                          "invalid socket number "%s" in " NGINX_VAR
                          " environment variable, ignoring", v);
        }
    
        ngx_inherited = 1;
        // 设置每个socket的详细配置信息,比如忽略无效的socket等等
        return ngx_set_inherited_sockets(cycle);
    }
    // core/ngx_connection.c
    ngx_int_t
    ngx_set_inherited_sockets(ngx_cycle_t *cycle)
    {
        size_t                     len;
        ngx_uint_t                 i;
        ngx_listening_t           *ls;
        socklen_t                  olen;
    #if (NGX_HAVE_DEFERRED_ACCEPT || NGX_HAVE_TCP_FASTOPEN)
        ngx_err_t                  err;
    #endif
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
        struct accept_filter_arg   af;
    #endif
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
        int                        timeout;
    #endif
    #if (NGX_HAVE_REUSEPORT)
        int                        reuseport;
    #endif
    
        ls = cycle->listening.elts;
        for (i = 0; i < cycle->listening.nelts; i++) {
    
            ls[i].sockaddr = ngx_palloc(cycle->pool, sizeof(ngx_sockaddr_t));
            if (ls[i].sockaddr == NULL) {
                return NGX_ERROR;
            }
    
            ls[i].socklen = sizeof(ngx_sockaddr_t);
            // 忽略无效的监听
            if (getsockname(ls[i].fd, ls[i].sockaddr, &ls[i].socklen) == -1) {
                ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
                              "getsockname() of the inherited "
                              "socket #%d failed", ls[i].fd);
                ls[i].ignore = 1;
                continue;
            }
    
            if (ls[i].socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
                ls[i].socklen = sizeof(ngx_sockaddr_t);
            }
    
            switch (ls[i].sockaddr->sa_family) {
    
    #if (NGX_HAVE_INET6)
            case AF_INET6:
                ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN;
                len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1;
                break;
    #endif
    
    #if (NGX_HAVE_UNIX_DOMAIN)
            case AF_UNIX:
                ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
                len = NGX_UNIX_ADDRSTRLEN;
                break;
    #endif
    
            case AF_INET:
                ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN;
                len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
                break;
    
            default:
                ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
                              "the inherited socket #%d has "
                              "an unsupported protocol family", ls[i].fd);
                ls[i].ignore = 1;
                continue;
            }
    
            ls[i].addr_text.data = ngx_pnalloc(cycle->pool, len);
            if (ls[i].addr_text.data == NULL) {
                return NGX_ERROR;
            }
    
            len = ngx_sock_ntop(ls[i].sockaddr, ls[i].socklen,
                                ls[i].addr_text.data, len, 1);
            if (len == 0) {
                return NGX_ERROR;
            }
    
            ls[i].addr_text.len = len;
    
            ls[i].backlog = NGX_LISTEN_BACKLOG;
    
            olen = sizeof(int);
    
            if (getsockopt(ls[i].fd, SOL_SOCKET, SO_TYPE, (void *) &ls[i].type,
                           &olen)
                == -1)
            {
                ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
                              "getsockopt(SO_TYPE) %V failed", &ls[i].addr_text);
                ls[i].ignore = 1;
                continue;
            }
    
            olen = sizeof(int);
    
            if (getsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (void *) &ls[i].rcvbuf,
                           &olen)
                == -1)
            {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
                              "getsockopt(SO_RCVBUF) %V failed, ignored",
                              &ls[i].addr_text);
    
                ls[i].rcvbuf = -1;
            }
    
            olen = sizeof(int);
    
            if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF, (void *) &ls[i].sndbuf,
                           &olen)
                == -1)
            {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
                              "getsockopt(SO_SNDBUF) %V failed, ignored",
                              &ls[i].addr_text);
    
                ls[i].sndbuf = -1;
            }
    
    #if 0
            /* SO_SETFIB is currently a set only option */
    
    #if (NGX_HAVE_SETFIB)
    
            olen = sizeof(int);
    
            if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
                           (void *) &ls[i].setfib, &olen)
                == -1)
            {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
                              "getsockopt(SO_SETFIB) %V failed, ignored",
                              &ls[i].addr_text);
    
                ls[i].setfib = -1;
            }
    
    #endif
    #endif
    
    #if (NGX_HAVE_REUSEPORT)
    
            reuseport = 0;
            olen = sizeof(int);
    
    #ifdef SO_REUSEPORT_LB
    
            if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT_LB,
                           (void *) &reuseport, &olen)
                == -1)
            {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
                              "getsockopt(SO_REUSEPORT_LB) %V failed, ignored",
                              &ls[i].addr_text);
    
            } else {
                ls[i].reuseport = reuseport ? 1 : 0;
            }
    
    #else
    
            if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
                           (void *) &reuseport, &olen)
                == -1)
            {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
                              "getsockopt(SO_REUSEPORT) %V failed, ignored",
                              &ls[i].addr_text);
    
            } else {
                ls[i].reuseport = reuseport ? 1 : 0;
            }
    #endif
    
    #endif
    
            if (ls[i].type != SOCK_STREAM) {
                continue;
            }
    
    #if (NGX_HAVE_TCP_FASTOPEN)
    
            olen = sizeof(int);
    
            if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
                           (void *) &ls[i].fastopen, &olen)
                == -1)
            {
                err = ngx_socket_errno;
    
                if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT
                    && err != NGX_EINVAL)
                {
                    ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
                                  "getsockopt(TCP_FASTOPEN) %V failed, ignored",
                                  &ls[i].addr_text);
                }
    
                ls[i].fastopen = -1;
            }
    
    #endif
    
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
    
            ngx_memzero(&af, sizeof(struct accept_filter_arg));
            olen = sizeof(struct accept_filter_arg);
    
            if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen)
                == -1)
            {
                err = ngx_socket_errno;
    
                if (err == NGX_EINVAL) {
                    continue;
                }
    
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
                              "getsockopt(SO_ACCEPTFILTER) for %V failed, ignored",
                              &ls[i].addr_text);
                continue;
            }
    
            if (olen < sizeof(struct accept_filter_arg) || af.af_name[0] == '') {
                continue;
            }
    
            ls[i].accept_filter = ngx_palloc(cycle->pool, 16);
            if (ls[i].accept_filter == NULL) {
                return NGX_ERROR;
            }
    
            (void) ngx_cpystrn((u_char *) ls[i].accept_filter,
                               (u_char *) af.af_name, 16);
    #endif
    
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
    
            timeout = 0;
            olen = sizeof(int);
    
            if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen)
                == -1)
            {
                err = ngx_socket_errno;
    
                if (err == NGX_EOPNOTSUPP) {
                    continue;
                }
    
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
                              "getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored",
                              &ls[i].addr_text);
                continue;
            }
    
            if (olen < sizeof(int) || timeout == 0) {
                continue;
            }
    
            ls[i].deferred_accept = 1;
    #endif
        }
    
        return NGX_OK;
    }
    View Code

    四、各模块的载入

      在main函数中只有 ngx_preinit_modules, 该方法只会给各module做编号处理,而 ngx_load_module 则会查找外部定义好的模块信息。

    // core/ngx_module.c
    ngx_int_t
    ngx_preinit_modules(void)
    {
        ngx_uint_t  i;
        // ngx_modules, ngx_module_names 这两个变量会在加载时初始化
        for (i = 0; ngx_modules[i]; i++) {
            ngx_modules[i]->index = i;
            ngx_modules[i]->name = ngx_module_names[i];
        }
    
        ngx_modules_n = i;
        // NGX_MAX_DYNAMIC_MODULES:128
        ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES;
    
        return NGX_OK;
    }
    // nginx.c
    static char *
    ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
    {
    #if (NGX_HAVE_DLOPEN)
        void                *handle;
        char               **names, **order;
        ngx_str_t           *value, file;
        ngx_uint_t           i;
        ngx_module_t        *module, **modules;
        ngx_pool_cleanup_t  *cln;
    
        if (cf->cycle->modules_used) {
            return "is specified too late";
        }
    
        value = cf->args->elts;
    
        file = value[1];
    
        if (ngx_conf_full_name(cf->cycle, &file, 0) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    
        cln = ngx_pool_cleanup_add(cf->cycle->pool, 0);
        if (cln == NULL) {
            return NGX_CONF_ERROR;
        }
    
        handle = ngx_dlopen(file.data);
        if (handle == NULL) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               ngx_dlopen_n " "%s" failed (%s)",
                               file.data, ngx_dlerror());
            return NGX_CONF_ERROR;
        }
    
        cln->handler = ngx_unload_module;
        cln->data = handle;
    
        modules = ngx_dlsym(handle, "ngx_modules");
        if (modules == NULL) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               ngx_dlsym_n " "%V", "%s" failed (%s)",
                               &value[1], "ngx_modules", ngx_dlerror());
            return NGX_CONF_ERROR;
        }
    
        names = ngx_dlsym(handle, "ngx_module_names");
        if (names == NULL) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               ngx_dlsym_n " "%V", "%s" failed (%s)",
                               &value[1], "ngx_module_names", ngx_dlerror());
            return NGX_CONF_ERROR;
        }
    
        order = ngx_dlsym(handle, "ngx_module_order");
    
        for (i = 0; modules[i]; i++) {
            module = modules[i];
            module->name = names[i];
    
            if (ngx_add_module(cf, &file, module, order) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
    
            ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, "module: %s i:%ui",
                           module->name, module->index);
        }
    
        return NGX_CONF_OK;
    
    #else
    
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           ""load_module" is not supported "
                           "on this platform");
        return NGX_CONF_ERROR;
    
    #endif
    }

    五、初始化全局控制变量 ngx_cycle

      ngx_cycle 是一个nginx中的重量级变量,和redis中的server变量一样。里面存储着各种配置信息,初始化socket监听,各模块的调度方式等等。

    // core/ngx_cycle.c  初始化cycle信息
    ngx_cycle_t *
    ngx_init_cycle(ngx_cycle_t *old_cycle)
    {
        void                *rv;
        char               **senv;
        ngx_uint_t           i, n;
        ngx_log_t           *log;
        ngx_time_t          *tp;
        ngx_conf_t           conf;
        ngx_pool_t          *pool;
        ngx_cycle_t         *cycle, **old;
        ngx_shm_zone_t      *shm_zone, *oshm_zone;
        ngx_list_part_t     *part, *opart;
        ngx_open_file_t     *file;
        ngx_listening_t     *ls, *nls;
        ngx_core_conf_t     *ccf, *old_ccf;
        ngx_core_module_t   *module;
        char                 hostname[NGX_MAXHOSTNAMELEN];
    
        ngx_timezone_update();
    
        /* force localtime update with a new timezone */
    
        tp = ngx_timeofday();
        tp->sec = 0;
    
        ngx_time_update();
    
    
        log = old_cycle->log;
    
        pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
        if (pool == NULL) {
            return NULL;
        }
        pool->log = log;
    
        cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));
        if (cycle == NULL) {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        cycle->pool = pool;
        cycle->log = log;
        // 将old_cycle赋值到变量中,并依次将其中的各配置提取出来
        cycle->old_cycle = old_cycle;
    
        cycle->conf_prefix.len = old_cycle->conf_prefix.len;
        cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
        if (cycle->conf_prefix.data == NULL) {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        cycle->prefix.len = old_cycle->prefix.len;
        cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix);
        if (cycle->prefix.data == NULL) {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        cycle->conf_file.len = old_cycle->conf_file.len;
        cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1);
        if (cycle->conf_file.data == NULL) {
            ngx_destroy_pool(pool);
            return NULL;
        }
        ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
                    old_cycle->conf_file.len + 1);
    
        cycle->conf_param.len = old_cycle->conf_param.len;
        cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
        if (cycle->conf_param.data == NULL) {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
    
        n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
    
        if (ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *))
            != NGX_OK)
        {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        ngx_memzero(cycle->paths.elts, n * sizeof(ngx_path_t *));
    
    
        if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))
            != NGX_OK)
        {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        ngx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel,
                        ngx_str_rbtree_insert_value);
    
        if (old_cycle->open_files.part.nelts) {
            n = old_cycle->open_files.part.nelts;
            for (part = old_cycle->open_files.part.next; part; part = part->next) {
                n += part->nelts;
            }
    
        } else {
            n = 20;
        }
    
        if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
            != NGX_OK)
        {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
    
        if (old_cycle->shared_memory.part.nelts) {
            n = old_cycle->shared_memory.part.nelts;
            for (part = old_cycle->shared_memory.part.next; part; part = part->next)
            {
                n += part->nelts;
            }
    
        } else {
            n = 1;
        }
    
        if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))
            != NGX_OK)
        {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
    
        if (ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t))
            != NGX_OK)
        {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t));
    
    
        ngx_queue_init(&cycle->reusable_connections_queue);
    
    
        cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
        if (cycle->conf_ctx == NULL) {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
    
        if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        /* on Linux gethostname() silently truncates name that does not fit */
    
        hostname[NGX_MAXHOSTNAMELEN - 1] = '';
        cycle->hostname.len = ngx_strlen(hostname);
    
        cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len);
        if (cycle->hostname.data == NULL) {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);
    
        // 将 ngx_module 赋给 cycle->modules
        if (ngx_cycle_modules(cycle) != NGX_OK) {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        // 调用各模块的 create_conf() 
        for (i = 0; cycle->modules[i]; i++) {
            if (cycle->modules[i]->type != NGX_CORE_MODULE) {
                continue;
            }
    
            module = cycle->modules[i]->ctx;
    
            if (module->create_conf) {
                rv = module->create_conf(cycle);
                if (rv == NULL) {
                    ngx_destroy_pool(pool);
                    return NULL;
                }
                cycle->conf_ctx[cycle->modules[i]->index] = rv;
            }
        }
    
    
        senv = environ;
    
    
        ngx_memzero(&conf, sizeof(ngx_conf_t));
        /* STUB: init array ? */
        conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));
        if (conf.args == NULL) {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
        conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
        if (conf.temp_pool == NULL) {
            ngx_destroy_pool(pool);
            return NULL;
        }
    
    
        conf.ctx = cycle->conf_ctx;
        conf.cycle = cycle;
        conf.pool = pool;
        conf.log = log;
        conf.module_type = NGX_CORE_MODULE;
        conf.cmd_type = NGX_MAIN_CONF;
    
    #if 0
        log->log_level = NGX_LOG_DEBUG_ALL;
    #endif
    
        if (ngx_conf_param(&conf) != NGX_CONF_OK) {
            environ = senv;
            ngx_destroy_cycle_pools(&conf);
            return NULL;
        }
    
        if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
            environ = senv;
            ngx_destroy_cycle_pools(&conf);
            return NULL;
        }
    
        if (ngx_test_config && !ngx_quiet_mode) {
            ngx_log_stderr(0, "the configuration file %s syntax is ok",
                           cycle->conf_file.data);
        }
        // 调用各模块的 init_conf()
        for (i = 0; cycle->modules[i]; i++) {
            if (cycle->modules[i]->type != NGX_CORE_MODULE) {
                continue;
            }
    
            module = cycle->modules[i]->ctx;
    
            if (module->init_conf) {
                if (module->init_conf(cycle,
                                      cycle->conf_ctx[cycle->modules[i]->index])
                    == NGX_CONF_ERROR)
                {
                    environ = senv;
                    ngx_destroy_cycle_pools(&conf);
                    return NULL;
                }
            }
        }
    
        if (ngx_process == NGX_PROCESS_SIGNALLER) {
            return cycle;
        }
    
        ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
    
        if (ngx_test_config) {
    
            if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
                goto failed;
            }
    
        } else if (!ngx_is_init_cycle(old_cycle)) {
    
            /*
             * we do not create the pid file in the first ngx_init_cycle() call
             * because we need to write the demonized process pid
             */
    
            old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
                                                       ngx_core_module);
            if (ccf->pid.len != old_ccf->pid.len
                || ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0)
            {
                /* new pid file name */
    
                if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
                    goto failed;
                }
    
                ngx_delete_pidfile(old_cycle);
            }
        }
    
    
        if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) {
            goto failed;
        }
    
    
        if (ngx_create_paths(cycle, ccf->user) != NGX_OK) {
            goto failed;
        }
    
    
        if (ngx_log_open_default(cycle) != NGX_OK) {
            goto failed;
        }
    
        /* open the new files */
    
        part = &cycle->open_files.part;
        file = part->elts;
    
        for (i = 0; /* void */ ; i++) {
    
            if (i >= part->nelts) {
                if (part->next == NULL) {
                    break;
                }
                part = part->next;
                file = part->elts;
                i = 0;
            }
    
            if (file[i].name.len == 0) {
                continue;
            }
    
            file[i].fd = ngx_open_file(file[i].name.data,
                                       NGX_FILE_APPEND,
                                       NGX_FILE_CREATE_OR_OPEN,
                                       NGX_FILE_DEFAULT_ACCESS);
    
            ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
                           "log: %p %d "%s"",
                           &file[i], file[i].fd, file[i].name.data);
    
            if (file[i].fd == NGX_INVALID_FILE) {
                ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                              ngx_open_file_n " "%s" failed",
                              file[i].name.data);
                goto failed;
            }
    
    #if !(NGX_WIN32)
            if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
                ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                              "fcntl(FD_CLOEXEC) "%s" failed",
                              file[i].name.data);
                goto failed;
            }
    #endif
        }
    
        cycle->log = &cycle->new_log;
        pool->log = &cycle->new_log;
    
    
        /* create shared memory */
    
        part = &cycle->shared_memory.part;
        shm_zone = part->elts;
    
        for (i = 0; /* void */ ; i++) {
    
            if (i >= part->nelts) {
                if (part->next == NULL) {
                    break;
                }
                part = part->next;
                shm_zone = part->elts;
                i = 0;
            }
    
            if (shm_zone[i].shm.size == 0) {
                ngx_log_error(NGX_LOG_EMERG, log, 0,
                              "zero size shared memory zone "%V"",
                              &shm_zone[i].shm.name);
                goto failed;
            }
    
            shm_zone[i].shm.log = cycle->log;
    
            opart = &old_cycle->shared_memory.part;
            oshm_zone = opart->elts;
    
            for (n = 0; /* void */ ; n++) {
    
                if (n >= opart->nelts) {
                    if (opart->next == NULL) {
                        break;
                    }
                    opart = opart->next;
                    oshm_zone = opart->elts;
                    n = 0;
                }
    
                if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) {
                    continue;
                }
    
                if (ngx_strncmp(shm_zone[i].shm.name.data,
                                oshm_zone[n].shm.name.data,
                                shm_zone[i].shm.name.len)
                    != 0)
                {
                    continue;
                }
    
                if (shm_zone[i].tag == oshm_zone[n].tag
                    && shm_zone[i].shm.size == oshm_zone[n].shm.size
                    && !shm_zone[i].noreuse)
                {
                    shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
    #if (NGX_WIN32)
                    shm_zone[i].shm.handle = oshm_zone[n].shm.handle;
    #endif
    
                    if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)
                        != NGX_OK)
                    {
                        goto failed;
                    }
    
                    goto shm_zone_found;
                }
    
                break;
            }
    
            if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
                goto failed;
            }
    
            if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
                goto failed;
            }
    
            if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
                goto failed;
            }
    
        shm_zone_found:
    
            continue;
        }
    
    
        /* handle the listening sockets */
    
        if (old_cycle->listening.nelts) {
            ls = old_cycle->listening.elts;
            for (i = 0; i < old_cycle->listening.nelts; i++) {
                ls[i].remain = 0;
            }
    
            nls = cycle->listening.elts;
            for (n = 0; n < cycle->listening.nelts; n++) {
    
                for (i = 0; i < old_cycle->listening.nelts; i++) {
                    if (ls[i].ignore) {
                        continue;
                    }
    
                    if (ls[i].remain) {
                        continue;
                    }
    
                    if (ls[i].type != nls[n].type) {
                        continue;
                    }
    
                    if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen,
                                         ls[i].sockaddr, ls[i].socklen, 1)
                        == NGX_OK)
                    {
                        nls[n].fd = ls[i].fd;
                        nls[n].previous = &ls[i];
                        ls[i].remain = 1;
    
                        if (ls[i].backlog != nls[n].backlog) {
                            nls[n].listen = 1;
                        }
    
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
    
                        /*
                         * FreeBSD, except the most recent versions,
                         * could not remove accept filter
                         */
                        nls[n].deferred_accept = ls[i].deferred_accept;
    
                        if (ls[i].accept_filter && nls[n].accept_filter) {
                            if (ngx_strcmp(ls[i].accept_filter,
                                           nls[n].accept_filter)
                                != 0)
                            {
                                nls[n].delete_deferred = 1;
                                nls[n].add_deferred = 1;
                            }
    
                        } else if (ls[i].accept_filter) {
                            nls[n].delete_deferred = 1;
    
                        } else if (nls[n].accept_filter) {
                            nls[n].add_deferred = 1;
                        }
    #endif
    
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
    
                        if (ls[i].deferred_accept && !nls[n].deferred_accept) {
                            nls[n].delete_deferred = 1;
    
                        } else if (ls[i].deferred_accept != nls[n].deferred_accept)
                        {
                            nls[n].add_deferred = 1;
                        }
    #endif
    
    #if (NGX_HAVE_REUSEPORT)
                        if (nls[n].reuseport && !ls[i].reuseport) {
                            nls[n].add_reuseport = 1;
                        }
    #endif
    
                        break;
                    }
                }
    
                if (nls[n].fd == (ngx_socket_t) -1) {
                    nls[n].open = 1;
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
                    if (nls[n].accept_filter) {
                        nls[n].add_deferred = 1;
                    }
    #endif
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
                    if (nls[n].deferred_accept) {
                        nls[n].add_deferred = 1;
                    }
    #endif
                }
            }
    
        } else {
            ls = cycle->listening.elts;
            for (i = 0; i < cycle->listening.nelts; i++) {
                ls[i].open = 1;
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
                if (ls[i].accept_filter) {
                    ls[i].add_deferred = 1;
                }
    #endif
    #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
                if (ls[i].deferred_accept) {
                    ls[i].add_deferred = 1;
                }
    #endif
            }
        }
        // 开启socket监听,主要调用 socket(), bind(), listen() 等方法实现
        if (ngx_open_listening_sockets(cycle) != NGX_OK) {
            goto failed;
        }
    
        if (!ngx_test_config) {
            // 配置socket 监听相关属性
            ngx_configure_listening_sockets(cycle);
        }
    
    
        /* commit the new cycle configuration */
    
        if (!ngx_use_stderr) {
            (void) ngx_log_redirect_stderr(cycle);
        }
    
        pool->log = cycle->log;
        // 调用各模块的 init_module() 方法,让模块初始化各自信息
        if (ngx_init_modules(cycle) != NGX_OK) {
            /* fatal */
            exit(1);
        }
    
    
        /* close and delete stuff that lefts from an old cycle */
    
        /* free the unnecessary shared memory */
    
        opart = &old_cycle->shared_memory.part;
        oshm_zone = opart->elts;
    
        for (i = 0; /* void */ ; i++) {
    
            if (i >= opart->nelts) {
                if (opart->next == NULL) {
                    goto old_shm_zone_done;
                }
                opart = opart->next;
                oshm_zone = opart->elts;
                i = 0;
            }
    
            part = &cycle->shared_memory.part;
            shm_zone = part->elts;
    
            for (n = 0; /* void */ ; n++) {
    
                if (n >= part->nelts) {
                    if (part->next == NULL) {
                        break;
                    }
                    part = part->next;
                    shm_zone = part->elts;
                    n = 0;
                }
    
                if (oshm_zone[i].shm.name.len != shm_zone[n].shm.name.len) {
                    continue;
                }
    
                if (ngx_strncmp(oshm_zone[i].shm.name.data,
                                shm_zone[n].shm.name.data,
                                oshm_zone[i].shm.name.len)
                    != 0)
                {
                    continue;
                }
    
                if (oshm_zone[i].tag == shm_zone[n].tag
                    && oshm_zone[i].shm.size == shm_zone[n].shm.size
                    && !oshm_zone[i].noreuse)
                {
                    goto live_shm_zone;
                }
    
                break;
            }
    
            ngx_shm_free(&oshm_zone[i].shm);
    
        live_shm_zone:
    
            continue;
        }
    
    old_shm_zone_done:
    
    
        /* close the unnecessary listening sockets */
    
        ls = old_cycle->listening.elts;
        for (i = 0; i < old_cycle->listening.nelts; i++) {
    
            if (ls[i].remain || ls[i].fd == (ngx_socket_t) -1) {
                continue;
            }
    
            if (ngx_close_socket(ls[i].fd) == -1) {
                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                              ngx_close_socket_n " listening socket on %V failed",
                              &ls[i].addr_text);
            }
    
    #if (NGX_HAVE_UNIX_DOMAIN)
    
            if (ls[i].sockaddr->sa_family == AF_UNIX) {
                u_char  *name;
    
                name = ls[i].addr_text.data + sizeof("unix:") - 1;
    
                ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
                              "deleting socket %s", name);
    
                if (ngx_delete_file(name) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                                  ngx_delete_file_n " %s failed", name);
                }
            }
    
    #endif
        }
    
    
        /* close the unnecessary open files */
    
        part = &old_cycle->open_files.part;
        file = part->elts;
    
        for (i = 0; /* void */ ; i++) {
    
            if (i >= part->nelts) {
                if (part->next == NULL) {
                    break;
                }
                part = part->next;
                file = part->elts;
                i = 0;
            }
    
            if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {
                continue;
            }
    
            if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                              ngx_close_file_n " "%s" failed",
                              file[i].name.data);
            }
        }
    
        ngx_destroy_pool(conf.temp_pool);
    
        if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {
    
            ngx_destroy_pool(old_cycle->pool);
            cycle->old_cycle = NULL;
    
            return cycle;
        }
    
    
        if (ngx_temp_pool == NULL) {
            ngx_temp_pool = ngx_create_pool(128, cycle->log);
            if (ngx_temp_pool == NULL) {
                ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                              "could not create ngx_temp_pool");
                exit(1);
            }
    
            n = 10;
    
            if (ngx_array_init(&ngx_old_cycles, ngx_temp_pool, n,
                               sizeof(ngx_cycle_t *))
                != NGX_OK)
            {
                exit(1);
            }
    
            ngx_memzero(ngx_old_cycles.elts, n * sizeof(ngx_cycle_t *));
    
            ngx_cleaner_event.handler = ngx_clean_old_cycles;
            ngx_cleaner_event.log = cycle->log;
            ngx_cleaner_event.data = &dumb;
            dumb.fd = (ngx_socket_t) -1;
        }
    
        ngx_temp_pool->log = cycle->log;
    
        old = ngx_array_push(&ngx_old_cycles);
        if (old == NULL) {
            exit(1);
        }
        *old = old_cycle;
    
        if (!ngx_cleaner_event.timer_set) {
            ngx_add_timer(&ngx_cleaner_event, 30000);
            ngx_cleaner_event.timer_set = 1;
        }
        // 正常返回初始化好的 cycle
        return cycle;
    
    
    failed:
    
        if (!ngx_is_init_cycle(old_cycle)) {
            old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
                                                       ngx_core_module);
            if (old_ccf->environment) {
                environ = old_ccf->environment;
            }
        }
    
        /* rollback the new cycle configuration */
    
        part = &cycle->open_files.part;
        file = part->elts;
    
        for (i = 0; /* void */ ; i++) {
    
            if (i >= part->nelts) {
                if (part->next == NULL) {
                    break;
                }
                part = part->next;
                file = part->elts;
                i = 0;
            }
    
            if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {
                continue;
            }
    
            if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
                ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                              ngx_close_file_n " "%s" failed",
                              file[i].name.data);
            }
        }
    
        /* free the newly created shared memory */
    
        part = &cycle->shared_memory.part;
        shm_zone = part->elts;
    
        for (i = 0; /* void */ ; i++) {
    
            if (i >= part->nelts) {
                if (part->next == NULL) {
                    break;
                }
                part = part->next;
                shm_zone = part->elts;
                i = 0;
            }
    
            if (shm_zone[i].shm.addr == NULL) {
                continue;
            }
    
            opart = &old_cycle->shared_memory.part;
            oshm_zone = opart->elts;
    
            for (n = 0; /* void */ ; n++) {
    
                if (n >= opart->nelts) {
                    if (opart->next == NULL) {
                        break;
                    }
                    opart = opart->next;
                    oshm_zone = opart->elts;
                    n = 0;
                }
    
                if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) {
                    continue;
                }
    
                if (ngx_strncmp(shm_zone[i].shm.name.data,
                                oshm_zone[n].shm.name.data,
                                shm_zone[i].shm.name.len)
                    != 0)
                {
                    continue;
                }
    
                if (shm_zone[i].tag == oshm_zone[n].tag
                    && shm_zone[i].shm.size == oshm_zone[n].shm.size
                    && !shm_zone[i].noreuse)
                {
                    goto old_shm_zone_found;
                }
    
                break;
            }
    
            ngx_shm_free(&shm_zone[i].shm);
    
        old_shm_zone_found:
    
            continue;
        }
    
        if (ngx_test_config) {
            ngx_destroy_cycle_pools(&conf);
            return NULL;
        }
    
        ls = cycle->listening.elts;
        for (i = 0; i < cycle->listening.nelts; i++) {
            if (ls[i].fd == (ngx_socket_t) -1 || !ls[i].open) {
                continue;
            }
    
            if (ngx_close_socket(ls[i].fd) == -1) {
                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                              ngx_close_socket_n " %V failed",
                              &ls[i].addr_text);
            }
        }
    
        ngx_destroy_cycle_pools(&conf);
    
        return NULL;
    }

    六、处理发送给nginx的控制信号

      针对 nginx -s stop|reload 等信号时,nginx是如何处理的呢?实际上,它只会运行到 ngx_signal_process(), 向原有的nginx进程发送相应的kill命令就返回了。

    // ngx_cycle.c, 处理信号
    ngx_int_t
    ngx_signal_process(ngx_cycle_t *cycle, char *sig)
    {
        ssize_t           n;
        ngx_pid_t         pid;
        ngx_file_t        file;
        ngx_core_conf_t  *ccf;
        u_char            buf[NGX_INT64_LEN + 2];
    
        ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "signal process started");
        // 根据下标获取 core_module 配置信息
        ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
    
        ngx_memzero(&file, sizeof(ngx_file_t));
    
        file.name = ccf->pid;
        file.log = cycle->log;
    
        file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY,
                                NGX_FILE_OPEN, NGX_FILE_DEFAULT_ACCESS);
    
        if (file.fd == NGX_INVALID_FILE) {
            ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno,
                          ngx_open_file_n " "%s" failed", file.name.data);
            return 1;
        }
    
        n = ngx_read_file(&file, buf, NGX_INT64_LEN + 2, 0);
    
        if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          ngx_close_file_n " "%s" failed", file.name.data);
        }
    
        if (n == NGX_ERROR) {
            return 1;
        }
    
        while (n-- && (buf[n] == CR || buf[n] == LF)) { /* void */ }
    
        pid = ngx_atoi(buf, ++n);
    
        if (pid == (ngx_pid_t) NGX_ERROR) {
            ngx_log_error(NGX_LOG_ERR, cycle->log, 0,
                          "invalid PID number "%*s" in "%s"",
                          n, buf, file.name.data);
            return 1;
        }
        // 根据 sig 处理pid 进程状态
        return ngx_os_signal_process(cycle, sig, pid);
    
    }
    
    ngx_int_t
    ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_pid_t pid)
    {
        ngx_signal_t  *sig;
        // 遍历所有的 signals, 找到匹配的方法后响应
        for (sig = signals; sig->signo != 0; sig++) {
            if (ngx_strcmp(name, sig->name) == 0) {
                // 操作系统只进行 kill 调用即可
                // 而该命令会被正运行的master进程接收到,做后续处理。
                if (kill(pid, sig->signo) != -1) {
                    return 0;
                }
    
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "kill(%P, %d) failed", pid, sig->signo);
            }
        }
    
        return 1;
    }
    // nginx 定义的各种signal
    typedef struct {
        int     signo;
        char   *signame;
        char   *name;
        void  (*handler)(int signo, siginfo_t *siginfo, void *ucontext);
    } ngx_signal_t;
    // os/unix/ngx_process.c
    ngx_signal_t  signals[] = {
        { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),    /* signo SIGHUP */
          "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),    /* *signame */
          "reload",                                    /* *name */
          ngx_signal_handler },                        /* *handler */
    
        { ngx_signal_value(NGX_REOPEN_SIGNAL),        /* signo SIGINFO */ 
          "SIG" ngx_value(NGX_REOPEN_SIGNAL),
          "reopen",
          ngx_signal_handler },
    
        { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
          "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
          "",
          ngx_signal_handler },
    
        { ngx_signal_value(NGX_TERMINATE_SIGNAL),    /* signo SIGTERM */
          "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
          "stop",
          ngx_signal_handler },
    
        { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),    /* signo SIGQUIT */    
          "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
          "quit",
          ngx_signal_handler },
    
        { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
          "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
          "",
          ngx_signal_handler },
    
        { SIGALRM, "SIGALRM", "", ngx_signal_handler },
    
        { SIGINT, "SIGINT", "", ngx_signal_handler },
    
        { SIGIO, "SIGIO", "", ngx_signal_handler },
    
        { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
    
        { SIGSYS, "SIGSYS, SIG_IGN", "", NULL },
    
        { SIGPIPE, "SIGPIPE, SIG_IGN", "", NULL },
    
        { 0, NULL, "", NULL }
    };

    七、master循环服务与worker进程循环服务

      main方法运行到最后,一定是以死循环的形式呈现服务的。而 ngx_master_process_cycle 则是处理这两个事情的函数。其主要作用就是,根据配置参数启动worker进程并进入循环服务,自身以master进程地形式运行循环服务。

    // os/unix/ngx_process_cycle.c, 主循环服务
    void
    ngx_master_process_cycle(ngx_cycle_t *cycle)
    {
        char              *title;
        u_char            *p;
        size_t             size;
        ngx_int_t          i;
        ngx_uint_t         n, sigio;
        sigset_t           set;
        struct itimerval   itv;
        ngx_uint_t         live;
        ngx_msec_t         delay;
        ngx_listening_t   *ls;
        ngx_core_conf_t   *ccf;
    
        sigemptyset(&set);
        sigaddset(&set, SIGCHLD);
        sigaddset(&set, SIGALRM);
        sigaddset(&set, SIGIO);
        sigaddset(&set, SIGINT);
        sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
        sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
        sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL));
        sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL));
        sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
        sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));
    
        if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "sigprocmask() failed");
        }
    
        sigemptyset(&set);
    
        // master process
        size = sizeof(master_process);
    
        for (i = 0; i < ngx_argc; i++) {
            size += ngx_strlen(ngx_argv[i]) + 1;
        }
    
        title = ngx_pnalloc(cycle->pool, size);
        if (title == NULL) {
            /* fatal */
            exit(2);
        }
    
        p = ngx_cpymem(title, master_process, sizeof(master_process) - 1);
        for (i = 0; i < ngx_argc; i++) {
            *p++ = ' ';
            p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size);
        }
    
        ngx_setproctitle(title);
    
    
        ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
        // 开启请求处理子进程 "worker process"
        ngx_start_worker_processes(cycle, ccf->worker_processes,
                                   NGX_PROCESS_RESPAWN);
        // 开启管理进程 "cache manager" / "cache loader" 
        ngx_start_cache_manager_processes(cycle, 0);
    
        ngx_new_binary = 0;
        delay = 0;
        sigio = 0;
        live = 1;
        // master 进程主循环服务
        // 监听外部各种控制信号
        for ( ;; ) {
            if (delay) {
                if (ngx_sigalrm) {
                    sigio = 0;
                    delay *= 2;
                    ngx_sigalrm = 0;
                }
    
                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "termination cycle: %M", delay);
    
                itv.it_interval.tv_sec = 0;
                itv.it_interval.tv_usec = 0;
                itv.it_value.tv_sec = delay / 1000;
                itv.it_value.tv_usec = (delay % 1000 ) * 1000;
    
                if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                                  "setitimer() failed");
                }
            }
    
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend");
    
            sigsuspend(&set);
    
            ngx_time_update();
    
            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "wake up, sigio %i", sigio);
    
            if (ngx_reap) {
                ngx_reap = 0;
                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");
    
                live = ngx_reap_children(cycle);
            }
            // master 进程退出,删除pid文件,关闭socket监听等等
            if (!live && (ngx_terminate || ngx_quit)) {
                ngx_master_process_exit(cycle);
            }
    
            if (ngx_terminate) {
                if (delay == 0) {
                    delay = 50;
                }
    
                if (sigio) {
                    sigio--;
                    continue;
                }
    
                sigio = ccf->worker_processes + 2 /* cache processes */;
                // 通知子进程进行关闭处理
                if (delay > 1000) {
                    ngx_signal_worker_processes(cycle, SIGKILL);
                } else {
                    ngx_signal_worker_processes(cycle,
                                           ngx_signal_value(NGX_TERMINATE_SIGNAL));
                }
    
                continue;
            }
    
            if (ngx_quit) {
                ngx_signal_worker_processes(cycle,
                                            ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
    
                ls = cycle->listening.elts;
                for (n = 0; n < cycle->listening.nelts; n++) {
                    if (ngx_close_socket(ls[n].fd) == -1) {
                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                                      ngx_close_socket_n " %V failed",
                                      &ls[n].addr_text);
                    }
                }
                cycle->listening.nelts = 0;
    
                continue;
            }
            // 重启nginx服务
            if (ngx_reconfigure) {
                ngx_reconfigure = 0;
                // new_binary
                if (ngx_new_binary) {
                    ngx_start_worker_processes(cycle, ccf->worker_processes,
                                               NGX_PROCESS_RESPAWN);
                    ngx_start_cache_manager_processes(cycle, 0);
                    ngx_noaccepting = 0;
    
                    continue;
                }
    
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");
                // 重新初始化 cycle 信息
                cycle = ngx_init_cycle(cycle);
                if (cycle == NULL) {
                    cycle = (ngx_cycle_t *) ngx_cycle;
                    continue;
                }
                // 重启子进程
                ngx_cycle = cycle;
                ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
                                                       ngx_core_module);
                ngx_start_worker_processes(cycle, ccf->worker_processes,
                                           NGX_PROCESS_JUST_RESPAWN);
                ngx_start_cache_manager_processes(cycle, 1);
    
                /* allow new processes to start */
                ngx_msleep(100);
    
                live = 1;
                ngx_signal_worker_processes(cycle,
                                            ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
            }
    
            if (ngx_restart) {
                ngx_restart = 0;
                ngx_start_worker_processes(cycle, ccf->worker_processes,
                                           NGX_PROCESS_RESPAWN);
                ngx_start_cache_manager_processes(cycle, 0);
                live = 1;
            }
    
            if (ngx_reopen) {
                ngx_reopen = 0;
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
                ngx_reopen_files(cycle, ccf->user);
                ngx_signal_worker_processes(cycle,
                                            ngx_signal_value(NGX_REOPEN_SIGNAL));
            }
    
            if (ngx_change_binary) {
                ngx_change_binary = 0;
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
                ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
            }
    
            if (ngx_noaccept) {
                ngx_noaccept = 0;
                ngx_noaccepting = 1;
                ngx_signal_worker_processes(cycle,
                                            ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
            }
        }
    }
    // ngx_process_cycle.c, 依据配置信息,开启子进程循环服务
    static void
    ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
    {
        ngx_int_t      i;
        ngx_channel_t  ch;
    
        ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
    
        ngx_memzero(&ch, sizeof(ngx_channel_t));
    
        ch.command = NGX_CMD_OPEN_CHANNEL;
    
        for (i = 0; i < n; i++) {
            // 创建子进程,然后运行 ngx_worker_process_cycle 逻辑
            ngx_spawn_process(cycle, ngx_worker_process_cycle,
                              (void *) (intptr_t) i, "worker process", type);
    
            ch.pid = ngx_processes[ngx_process_slot].pid;
            ch.slot = ngx_process_slot;
            ch.fd = ngx_processes[ngx_process_slot].channel[0];
    
            ngx_pass_open_channel(cycle, &ch);
        }
    }
    // ngx_process.c, 创建子进程
    ngx_pid_t
    ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
        char *name, ngx_int_t respawn)
    {
        u_long     on;
        ngx_pid_t  pid;
        ngx_int_t  s;
    
        if (respawn >= 0) {
            s = respawn;
    
        } else {
            for (s = 0; s < ngx_last_process; s++) {
                if (ngx_processes[s].pid == -1) {
                    break;
                }
            }
    
            if (s == NGX_MAX_PROCESSES) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                              "no more than %d processes can be spawned",
                              NGX_MAX_PROCESSES);
                return NGX_INVALID_PID;
            }
        }
    
    
        if (respawn != NGX_PROCESS_DETACHED) {
    
            /* Solaris 9 still has no AF_LOCAL */
    
            if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
            {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "socketpair() failed while spawning "%s"", name);
                return NGX_INVALID_PID;
            }
    
            ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                           "channel %d:%d",
                           ngx_processes[s].channel[0],
                           ngx_processes[s].channel[1]);
    
            if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              ngx_nonblocking_n " failed while spawning "%s"",
                              name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
            if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              ngx_nonblocking_n " failed while spawning "%s"",
                              name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
            on = 1;
            if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "ioctl(FIOASYNC) failed while spawning "%s"", name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
            if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "fcntl(F_SETOWN) failed while spawning "%s"", name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
            if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "fcntl(FD_CLOEXEC) failed while spawning "%s"",
                               name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
            if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "fcntl(FD_CLOEXEC) failed while spawning "%s"",
                               name);
                ngx_close_channel(ngx_processes[s].channel, cycle->log);
                return NGX_INVALID_PID;
            }
    
            ngx_channel = ngx_processes[s].channel[1];
    
        } else {
            ngx_processes[s].channel[0] = -1;
            ngx_processes[s].channel[1] = -1;
        }
    
        ngx_process_slot = s;
    
        // 创建子进程
        pid = fork();
    
        switch (pid) {
    
        case -1:
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "fork() failed while spawning "%s"", name);
            ngx_close_channel(ngx_processes[s].channel, cycle->log);
            return NGX_INVALID_PID;
    
        case 0:
            ngx_parent = ngx_pid;
            ngx_pid = ngx_getpid();
            // 子进程中直接调用 ngx_worker_process_cycle() 方法进行事务处理
            proc(cycle, data);
            break;
    
        default:
            // 父进程则直接返回了
            break;
        }
    
        ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
    
        ngx_processes[s].pid = pid;
        ngx_processes[s].exited = 0;
    
        if (respawn >= 0) {
            return pid;
        }
    
        ngx_processes[s].proc = proc;
        ngx_processes[s].data = data;
        ngx_processes[s].name = name;
        ngx_processes[s].exiting = 0;
    
        switch (respawn) {
    
        case NGX_PROCESS_NORESPAWN:
            ngx_processes[s].respawn = 0;
            ngx_processes[s].just_spawn = 0;
            ngx_processes[s].detached = 0;
            break;
    
        case NGX_PROCESS_JUST_SPAWN:
            ngx_processes[s].respawn = 0;
            ngx_processes[s].just_spawn = 1;
            ngx_processes[s].detached = 0;
            break;
    
        case NGX_PROCESS_RESPAWN:
            ngx_processes[s].respawn = 1;
            ngx_processes[s].just_spawn = 0;
            ngx_processes[s].detached = 0;
            break;
    
        case NGX_PROCESS_JUST_RESPAWN:
            ngx_processes[s].respawn = 1;
            ngx_processes[s].just_spawn = 1;
            ngx_processes[s].detached = 0;
            break;
    
        case NGX_PROCESS_DETACHED:
            ngx_processes[s].respawn = 0;
            ngx_processes[s].just_spawn = 0;
            ngx_processes[s].detached = 1;
            break;
        }
    
        if (s == ngx_last_process) {
            ngx_last_process++;
        }
    
        return pid;
    }
    
    // ngx_process_cycle.c, 子进程处理服务
    static void
    ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
    {
        ngx_int_t worker = (intptr_t) data;
    
        ngx_process = NGX_PROCESS_WORKER;
        ngx_worker = worker;
    
        ngx_worker_process_init(cycle, worker);
    
        ngx_setproctitle("worker process");
        // 子进程中的死循环服务,通过 ngx_process_events_and_timers 进行事件处理
        for ( ;; ) {
            // 当需要子进程退出时,会调用 ngx_worker_process_exit(), 并最终调用 exit(0); 直接退出而无需执行后续代码
            if (ngx_exiting) {
                if (ngx_event_no_timers_left() == NGX_OK) {
                    ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
                    ngx_worker_process_exit(cycle);
                }
            }
    
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
            // 主要逻辑处理如:网络事件 accept, read, 锁获取等等
            ngx_process_events_and_timers(cycle);
    
            if (ngx_terminate) {
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
                ngx_worker_process_exit(cycle);
            }
    
            if (ngx_quit) {
                ngx_quit = 0;
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
                              "gracefully shutting down");
                ngx_setproctitle("worker process is shutting down");
    
                if (!ngx_exiting) {
                    ngx_exiting = 1;
                    ngx_set_shutdown_timer(cycle);
                    ngx_close_listening_sockets(cycle);
                    ngx_close_idle_connections(cycle);
                }
            }
    
            if (ngx_reopen) {
                ngx_reopen = 0;
                ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
                ngx_reopen_files(cycle, -1);
            }
        }
    }

      到此,nginx整个启动流程就分析完了,有了个整体概念。再要研究,我们就得要针对具体的功能点来分析了。请听下回分解。

  • 相关阅读:
    李连杰开始做慈善事业了!
    世界是平的,这本书主要是写给美国人看的
    [问题征解]请解释下ubuntu 510 firefox的flash不发音的问题
    中医治疗慢性病很有效
    清理downloader病毒几百个,2个小时
    firefox2.0的拖放式搜索怎么不行了?是设置问题吗?
    spring live上有个入门的整合SSH的例子
    cctv的健康之路节目知识性和可看性都不错!
    跟你分享一下养生的经验
    cctv: 西医拒绝治疗的小孩,中医三天见效
  • 原文地址:https://www.cnblogs.com/yougewe/p/12642655.html
Copyright © 2020-2023  润新知