前几篇主要介绍了Nginx比较常用的一些基础数据结构,例如pool,buf,array,list等。通过对Nginx基础数据结构的理解,能更好的帮助我们读懂整个Nginx的源代码。
这一章节开始主要分析Nginx的主流程。
Nginx的主流程的实现函数在./src/core/nginx.c文件中。通过main()函数,我们可以窥探整个Nginx启动的流程。
main()函数的启动过程如下:
ngx_get_options方法主要用于解析命令行外部参数。例如:./nginx -s stop|start|restart
/* 解析外部参数 */ if (ngx_get_options(argc, argv) != NGX_OK) { return 1; }
/** * 解析启动命令行中的参数 * ./nginx -s stop|start|restart */ 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; case 'T': ngx_test_config = 1; ngx_dump_config = 1; break; case 'q': ngx_quiet_mode = 1; break; 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; 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; 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; }
初始化init_cycle Nginx的全局变量。在内存池上创建一个默认大小1024的全局变量。这里只是最简单的初始化一个变量。
/* * init_cycle->log is required for signal handlers and * ngx_process_options() */ /* 初始化Nginx的init_cycle */ ngx_memzero(&init_cycle, sizeof(ngx_cycle_t)); init_cycle.log = log; ngx_cycle = &init_cycle; /* 创建内存池 默认大小1024*/ init_cycle.pool = ngx_create_pool(1024, log); if (init_cycle.pool == NULL) { 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; }
ngx_save_argv:保存Nginx命令行中的参数和变量,放到全局变量ngx_argv
ngx_process_options:将ngx_get_options中获得这些参数取值赋值到ngx_cycle中。prefix, conf_prefix, conf_file, conf_param等字段。
/* 保存Nginx命令行中的参数和变量,放到全局变量ngx_argv */ if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) { return 1; } /* 将ngx_get_options中获得这些参数取值赋值到ngx_cycle中 */ if (ngx_process_options(&init_cycle) != NGX_OK) { return 1; }头部的全局变量定义
/** * 定义全局变量参数 */ static ngx_uint_t ngx_show_help; //是否显示帮助信息 static ngx_uint_t ngx_show_version; //是否显示版本号 static ngx_uint_t ngx_show_configure; //是否显示配置信息 static u_char *ngx_prefix; //Nginx的工作目录 static u_char *ngx_conf_file; //全局配置文件目录地址 static u_char *ngx_conf_params; //配置参数 static char *ngx_signal; //信号
int ngx_argc; //命令行参数个数 char **ngx_argv; //命令行参数 char **ngx_os_argv;
/** * 保存Nginx命令行中的参数和变量 * 放到全局变量ngx_argv */ static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv) { #if (NGX_FREEBSD) ngx_os_argv = (char **) argv; ngx_argc = argc; ngx_argv = (char **) argv; #else size_t len; ngx_int_t i; ngx_os_argv = (char **) argv; ngx_argc = argc; ngx_argv = ngx_alloc((argc + 1) * sizeof(char *), cycle->log); if (ngx_argv == NULL) { return NGX_ERROR; } for (i = 0; i < argc; i++) { len = ngx_strlen(argv[i]) + 1; ngx_argv[i] = ngx_alloc(len, cycle->log); if (ngx_argv[i] == NULL) { return NGX_ERROR; } (void) ngx_cpystrn((u_char *) ngx_argv[i], (u_char *) argv[i], len); } ngx_argv[i] = NULL; #endif ngx_os_environ = environ; return NGX_OK; }
/** * 将ngx_get_options中获得这些参数取值赋值到ngx_cycle中 */ static ngx_int_t ngx_process_options(ngx_cycle_t *cycle) { u_char *p; size_t len; /* Nginx工作目录 */ if (ngx_prefix) { len = ngx_strlen(ngx_prefix); p = ngx_prefix; if (len && !ngx_path_separator(p[len - 1])) { p = ngx_pnalloc(cycle->pool, len + 1); if (p == NULL) { return NGX_ERROR; } ngx_memcpy(p, ngx_prefix, len); p[len++] = '/'; } cycle->conf_prefix.len = len; cycle->conf_prefix.data = p; cycle->prefix.len = len; cycle->prefix.data = p; } else { #ifndef NGX_PREFIX p = ngx_pnalloc(cycle->pool, NGX_MAX_PATH); if (p == NULL) { return NGX_ERROR; } 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; #else #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 } /* 配置文件目录 */ if (ngx_conf_file) { cycle->conf_file.len = ngx_strlen(ngx_conf_file); cycle->conf_file.data = ngx_conf_file; } else { ngx_str_set(&cycle->conf_file, NGX_CONF_PATH); } 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--) { 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; } } /* 配置参数 */ 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; }
ngx_preinit_modules方法主要初始化所有模块;并对所有模块进行编号处理;
/* 初始化所有模块;并对所有模块进行编号处理; * ngx_modules数却是在自动编译的时候生成的,位于objs/ngx_modules.c文件中 */ if (ngx_preinit_modules() != NGX_OK) { return 1; }
/** * 初始化所有模块;并对所有模块进行编号处理; */ ngx_int_t ngx_preinit_modules(void) { ngx_uint_t i; 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_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES; return NGX_OK; }
ngx_create_pidfile创建PID文件
/* 创建PID文件 */ if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { return 1; }ngx_cycle.c
/** * 创建PID的文件 */ ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log) { size_t len; ngx_uint_t create; ngx_file_t file; u_char pid[NGX_INT64_LEN + 2]; if (ngx_process > NGX_PROCESS_MASTER) { return NGX_OK; } ngx_memzero(&file, sizeof(ngx_file_t)); file.name = *name; file.log = log; create = ngx_test_config ? NGX_FILE_CREATE_OR_OPEN : NGX_FILE_TRUNCATE; file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR, create, NGX_FILE_DEFAULT_ACCESS); if (file.fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, ngx_open_file_n " \"%s\" failed", file.name.data); return NGX_ERROR; } if (!ngx_test_config) { len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid; if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) { return NGX_ERROR; } } if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", file.name.data); } return NGX_OK; }
下面的模块都会新开文章具体详细解析:
ngx_add_inherited_sockets 继承Socket文件句柄
ngx_init_cycle 全局配置文件cycle详解
ngx_signal_process 信号的处理机制
ngx_master_process_cycle 多进程循环机制