void ngx_single_process_cycle(ngx_cycle_t *cycle) { ngx_uint_t i; if (ngx_set_environment(cycle, NULL) == NULL) { /* fatal */ exit(2); } for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } } } for ( ;; ) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); ngx_process_events_and_timers(cycle); if (ngx_terminate || ngx_quit) { for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->exit_process) { ngx_modules[i]->exit_process(cycle); } } ngx_master_process_exit(cycle); } if (ngx_reconfigure) { ngx_reconfigure = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, (ngx_uid_t) -1); } } }
PerlInterpreter * ngx_http_psgi_create_interpreter(ngx_conf_t *cf) { int n; PerlInterpreter *perl; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "Create PSGI Perl interpreter"); /* FIXME: Some code from ngx_http_perl_module.c I don't understand */ if (ngx_set_environment(cf->cycle, NULL) == NULL) { return NULL; } perl = perl_alloc(); if (perl == NULL) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_alloc() failed"); return NULL; } { char *my_argv[] = { "", "-MIO::Handle", "-e", "0" }; dTHXa(perl); PERL_SET_CONTEXT(perl); perl_construct(perl); n = perl_parse(perl, xs_init, 3, my_argv, NULL); if (n != 0) { ngx_log_error(NGX_LOG_ALERT, cf->log, 3, "perl_parse() failed: %d", n); goto fail; } PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_nginx_error)); } return perl; fail: (void) perl_destruct(perl); perl_free(perl); return NULL; }
ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) { char **env, *var; u_char *p; ngx_uint_t i, n; ngx_pid_t pid; ngx_exec_ctx_t ctx; ngx_core_conf_t *ccf; ngx_listening_t *ls; ngx_memzero(&ctx, sizeof(ngx_exec_ctx_t)); ctx.path = argv[0]; ctx.name = "new binary process"; ctx.argv = argv; n = 2; env = ngx_set_environment(cycle, &n); if (env == NULL) { return NGX_INVALID_PID; } var = ngx_alloc(sizeof(NGINX_VAR) + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2, cycle->log); p = ngx_cpymem(var, NGINX_VAR "=", sizeof(NGINX_VAR)); ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { p = ngx_sprintf(p, "%ud;", ls[i].fd); } *p = '\0'; env[n++] = var; #if (NGX_SETPROCTITLE_USES_ENV) /* allocate the spare 300 bytes for the new binary process title */ env[n++] = "SPARE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; #endif env[n] = NULL; #if (NGX_DEBUG) { char **e; for (e = env; *e; e++) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "env: %s", *e); } } #endif ctx.envp = (char *const *) env; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ngx_rename_file(ccf->pid.data, ccf->oldpid.data) != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_rename_file_n " %s to %s failed " "before executing new binary process \"%s\"", ccf->pid.data, ccf->oldpid.data, argv[0]); ngx_free(env); ngx_free(var); return NGX_INVALID_PID; } pid = ngx_execute(cycle, &ctx); if (pid == NGX_INVALID_PID) { if (ngx_rename_file(ccf->oldpid.data, ccf->pid.data) != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_rename_file_n " %s back to %s failed after " "the try to execute the new binary process \"%s\"", ccf->oldpid.data, ccf->pid.data, argv[0]); } } ngx_free(env); ngx_free(var); return pid; }
static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) { sigset_t set; uint64_t cpu_affinity; ngx_int_t n; ngx_uint_t i; struct rlimit rlmt; ngx_core_conf_t *ccf; ngx_listening_t *ls; if (ngx_set_environment(cycle, NULL) == NULL) { /* fatal */ exit(2); } ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (worker >= 0 && ccf->priority != 0) { if (setpriority(PRIO_PROCESS, 0, ccf->priority) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setpriority(%d) failed", ccf->priority); } } if (ccf->rlimit_nofile != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile; rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile; if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_NOFILE, %i) failed", ccf->rlimit_nofile); } } if (ccf->rlimit_core != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_core; rlmt.rlim_max = (rlim_t) ccf->rlimit_core; if (setrlimit(RLIMIT_CORE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_CORE, %O) failed", ccf->rlimit_core); } } #ifdef RLIMIT_SIGPENDING if (ccf->rlimit_sigpending != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_sigpending; rlmt.rlim_max = (rlim_t) ccf->rlimit_sigpending; if (setrlimit(RLIMIT_SIGPENDING, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_SIGPENDING, %i) failed", ccf->rlimit_sigpending); } } #endif if (geteuid() == 0) { if (setgid(ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setgid(%d) failed", ccf->group); /* fatal */ exit(2); } if (initgroups(ccf->username, ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "initgroups(%s, %d) failed", ccf->username, ccf->group); } if (setuid(ccf->user) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setuid(%d) failed", ccf->user); /* fatal */ exit(2); } } if (worker >= 0) { cpu_affinity = ngx_get_cpu_affinity(worker); if (cpu_affinity) { ngx_setaffinity(cpu_affinity, cycle->log); } } #if (NGX_HAVE_PR_SET_DUMPABLE) /* allow coredump after setuid() in Linux 2.4.x */ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "prctl(PR_SET_DUMPABLE) failed"); } #endif if (ccf->working_directory.len) { if (chdir((char *) ccf->working_directory.data) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "chdir(\"%s\") failed", ccf->working_directory.data); /* fatal */ exit(2); } } sigemptyset(&set); if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } srandom((ngx_pid << 16) ^ ngx_time()); /* * disable deleting previous events for the listening sockets because * in the worker processes there are no events at all at this point */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].previous = NULL; } for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } } } for (n = 0; n < ngx_last_process; n++) { if (ngx_processes[n].pid == -1) { continue; } if (n == ngx_process_slot) { continue; } if (ngx_processes[n].channel[1] == -1) { continue; } if (close(ngx_processes[n].channel[1]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); } } if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); } #if 0 ngx_last_process = 0; #endif if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT, ngx_channel_handler) == NGX_ERROR) { /* fatal */ exit(2); } }
/*[p]工作进程初始化*/ static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority) { sigset_t set; ngx_int_t n; ngx_uint_t i; struct rlimit rlmt; ngx_core_conf_t *ccf; ngx_listening_t *ls; //[p] 设置nginx服务器的运行环境 if (ngx_set_environment(cycle, NULL) == NULL) { /* fatal */ exit(2); } //[p]获取配置的上下文 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (priority && ccf->priority != 0) { if (setpriority(PRIO_PROCESS, 0, ccf->priority) == -1) { //[p] 设置工作进程优先级 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, //[p]出错处理 "setpriority(%d) failed", ccf->priority); } } if (ccf->rlimit_nofile != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile; //[p] 获取配置信息 rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile; if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) { //[p]设置打开文件描述符的上限 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_NOFILE, %i) failed", ccf->rlimit_nofile); } } if (ccf->rlimit_core != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_core; rlmt.rlim_max = (rlim_t) ccf->rlimit_core; if (setrlimit(RLIMIT_CORE, &rlmt) == -1) { //[p] 设置内核转储文件的最大长度 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_CORE, %O) failed", ccf->rlimit_core); } } #ifdef RLIMIT_SIGPENDING if (ccf->rlimit_sigpending != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_sigpending; rlmt.rlim_max = (rlim_t) ccf->rlimit_sigpending; if (setrlimit(RLIMIT_SIGPENDING, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_SIGPENDING, %i) failed", ccf->rlimit_sigpending); } } #endif if (geteuid() == 0) { if (setgid(ccf->group) == -1) { //[p]设置组ID ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setgid(%d) failed", ccf->group); /* fatal */ exit(2); } if (initgroups(ccf->username, ccf->group) == -1) { //[p] 初始化组清单 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "initgroups(%s, %d) failed", ccf->username, ccf->group); } if (setuid(ccf->user) == -1) { //[p] 设置用户ID ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setuid(%d) failed", ccf->user); /* fatal */ exit(2); } } #if (NGX_HAVE_SCHED_SETAFFINITY) if (cpu_affinity) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "sched_setaffinity(0x%08Xl)", cpu_affinity); if (sched_setaffinity(0, sizeof(cpu_affinity), (cpu_set_t *) &cpu_affinity) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sched_setaffinity(0x%08Xl) failed", cpu_affinity); } } #endif #if (NGX_HAVE_PR_SET_DUMPABLE) /* allow coredump after setuid() in Linux 2.4.x */ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "prctl(PR_SET_DUMPABLE) failed"); } #endif if (ccf->working_directory.len) { if (chdir((char *) ccf->working_directory.data) == -1) { //[p]设置进程的工作目录 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "chdir(\"%s\") failed", ccf->working_directory.data); /* fatal */ exit(2); } } sigemptyset(&set); if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) { //[p] 取消最信号的屏蔽 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } /* * disable deleting previous events for the listening sockets because * in the worker processes there are no events at all at this point */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].previous = NULL; //[p] 遍历并设置所有监听套接字的状态 } //[p] 初始化nginx各个模块 for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { //进程初始化, 调用每个模块的init_process,用它做模块开发的时候,使用得挺少的 //这里要特别看的是event模块: //nginx的event模块包含一个init_process,也就是ngx_event_process_init(ngx_event.c). //这个函数就是nginx的驱动器,他初始化事件驱动器,连接池,定时器,以及挂在listen 句柄的回调函数 if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } } } // 这里循环用户关闭其他worker进程的无用channel资源 for (n = 0; n < ngx_last_process; n++) { if (ngx_processes[n].pid == -1) { //n位置的进程不存在,这里是预防性的代码 continue; } //ngx_process_slot是创建worker进程的时候,从master进程复制过来的,此处就是指本worker进程在数组中的索引位置 if (n == ngx_process_slot) { continue; } if (ngx_processes[n].channel[1] == -1) { // channel不存在,跳过 continue; } // 创建worker进程时,会将master的资源复制过来,因此需要关闭无用的channel -- 其他worker进程的读端描述符 if (close(ngx_processes[n].channel[1]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); } } // 关闭本worker进程的channel的写端描述符。 if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); } #if 0 ngx_last_process = 0; #endif // 将channel放入nginx关心的集合中,同时关注channel上的读事件。 //[p] 设置当前工作进程从channel[1]中监听事件 if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT, ngx_channel_handler) == NGX_ERROR) { /* fatal */ exit(2); } }
static PerlInterpreter * ngx_http_perl_create_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf) { int n; STRLEN len; SV *sv; char *ver, *embedding[6]; PerlInterpreter *perl; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter"); if (ngx_set_environment(cf->cycle, NULL) == NULL) { return NULL; } perl = perl_alloc(); if (perl == NULL) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_alloc() failed"); return NULL; } { dTHXa(perl); PERL_SET_CONTEXT(perl); perl_construct(perl); #ifdef PERL_EXIT_DESTRUCT_END PL_exit_flags |= PERL_EXIT_DESTRUCT_END; #endif embedding[0] = ""; if (pmcf->modules.data) { embedding[1] = "-I"; embedding[2] = (char *) pmcf->modules.data; n = 3; } else { n = 1; } embedding[n++] = "-Mnginx"; embedding[n++] = "-e"; embedding[n++] = "0"; n = perl_parse(perl, ngx_http_perl_xs_init, n, embedding, NULL); if (n != 0) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_parse() failed: %d", n); goto fail; } sv = get_sv("nginx::VERSION", FALSE); ver = SvPV(sv, len); if (ngx_strcmp(ver, NGINX_VERSION) != 0) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "version " NGINX_VERSION " of nginx.pm is required, " "but %s was found", ver); goto fail; } if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) != NGX_OK) { goto fail; } } return perl; fail: (void) perl_destruct(perl); perl_free(perl); return NULL; }
static char * ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf) { #if (NGX_HAVE_PERL_MULTIPLICITY) ngx_pool_cleanup_t *cln; cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NGX_CONF_ERROR; } #else static PerlInterpreter *perl; #endif #ifdef NGX_PERL_MODULES if (pmcf->modules.data == NULL) { pmcf->modules.data = NGX_PERL_MODULES; } #endif if (pmcf->modules.data) { if (ngx_conf_full_name(cf->cycle, &pmcf->modules, 0) != NGX_OK) { return NGX_CONF_ERROR; } } #if !(NGX_HAVE_PERL_MULTIPLICITY) if (perl) { if (ngx_set_environment(cf->cycle, NULL) == NULL) { return NGX_CONF_ERROR; } if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) != NGX_OK) { return NGX_CONF_ERROR; } pmcf->perl = perl; pmcf->nginx = nginx_stash; return NGX_CONF_OK; } #endif if (nginx_stash == NULL) { PERL_SYS_INIT(&ngx_argc, &ngx_argv); } pmcf->perl = ngx_http_perl_create_interpreter(cf, pmcf); if (pmcf->perl == NULL) { return NGX_CONF_ERROR; } pmcf->nginx = nginx_stash; #if (NGX_HAVE_PERL_MULTIPLICITY) cln->handler = ngx_http_perl_cleanup_perl; cln->data = pmcf->perl; #else perl = pmcf->perl; #endif return NGX_CONF_OK; }
static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) { sigset_t set; ngx_int_t n; ngx_uint_t i; ngx_cpuset_t *cpu_affinity; struct rlimit rlmt; ngx_core_conf_t *ccf; ngx_listening_t *ls; if (ngx_set_environment(cycle, NULL) == NULL) { /* fatal */ exit(2); } ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (worker >= 0 && ccf->priority != 0) { /*设置工作进程优先级*/ if (setpriority(PRIO_PROCESS, 0, ccf->priority) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setpriority(%d) failed", ccf->priority); } } if (ccf->rlimit_nofile != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile; rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile; /*设置工作进程可打开的文件描述符的最大数*/ if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_NOFILE, %i) failed", ccf->rlimit_nofile); } } if (ccf->rlimit_core != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_core; rlmt.rlim_max = (rlim_t) ccf->rlimit_core; /*设置工作进程可生成的core文件的最大大小*/ if (setrlimit(RLIMIT_CORE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_CORE, %O) failed", ccf->rlimit_core); } } if (geteuid() == 0) { /*设置组ID*/ if (setgid(ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setgid(%d) failed", ccf->group); /* fatal */ exit(2); } /*初始化组清单*/ if (initgroups(ccf->username, ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "initgroups(%s, %d) failed", ccf->username, ccf->group); } /*设置用户ID*/ if (setuid(ccf->user) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setuid(%d) failed", ccf->user); /* fatal */ exit(2); } } if (worker >= 0) { /*获取配置文件中的worker_cpu_affinit指令的配置*/ cpu_affinity = ngx_get_cpu_affinity(worker); if (cpu_affinity) { /*解析并使配置生效,为工作进程分配CPU的工作内核*/ ngx_setaffinity(cpu_affinity, cycle->log); } } #if (NGX_HAVE_PR_SET_DUMPABLE) /* allow coredump after setuid() in Linux 2.4.x */ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "prctl(PR_SET_DUMPABLE) failed"); } #endif if (ccf->working_directory.len) { /*设置进程的工作目录,工作进程在执行过程中会在当前目录下写入运行数据,因此需要对工作目录有相应的权限*/ if (chdir((char *) ccf->working_directory.data) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "chdir(\"%s\") failed", ccf->working_directory.data); /* fatal */ exit(2); } } /*取消对所有信号的屏蔽*/ sigemptyset(&set); if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } srandom((ngx_pid << 16) ^ ngx_time()); /* * disable deleting previous events for the listening sockets because * in the worker processes there are no events at all at this point */ /*遍历并设置所有监听套接字的状态*/ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].previous = NULL; } for (i = 0; cycle->modules[i]; i++) { if (cycle->modules[i]->init_process) { /*初始化Nginx各个模块*/ if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } } } /*遍历所有其他的工作进程,调用close()将它们用于监听的channel[1]关闭*/ for (n = 0; n < ngx_last_process; n++) { if (ngx_processes[n].pid == -1) { continue; } /*判断是否为当前的工作进程*/ if (n == ngx_process_slot) { continue; } /*判断进程间通信管道是否正常*/ if (ngx_processes[n].channel[1] == -1) { continue; } /*关闭其他进程的channel[1]*/ if (close(ngx_processes[n].channel[1]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); } } /*然后将当前工作进程用于发送消息的channel[0]关闭,只留下channel[1]监听事件的到来*/ if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); } #if 0 ngx_last_process = 0; #endif /*添加管道读取事件,回调函数ngx_channel_handler中,无限循环从管道中读取数据,根据数据内容设置一些全局变量开关*/ /*添加事件使用ngx_event_actions.add*/ if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT, ngx_channel_handler) == NGX_ERROR) { /* fatal */ exit(2); } }
static PerlInterpreter * ngx_http_perl_create_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf) { int n; STRLEN len; SV *sv; char *ver, **embedding; ngx_str_t *m; ngx_uint_t i; PerlInterpreter *perl; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter"); if (ngx_set_environment(cf->cycle, NULL) == NULL) { return NULL; } perl = perl_alloc(); if (perl == NULL) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_alloc() failed"); return NULL; } { dTHXa(perl); PERL_SET_CONTEXT(perl); perl_construct(perl); #ifdef PERL_EXIT_DESTRUCT_END PL_exit_flags |= PERL_EXIT_DESTRUCT_END; #endif n = (pmcf->modules != NGX_CONF_UNSET_PTR) ? pmcf->modules->nelts * 2 : 0; embedding = ngx_palloc(cf->pool, (4 + n) * sizeof(char *)); if (embedding == NULL) { goto fail; } embedding[0] = ""; if (n++) { m = pmcf->modules->elts; for (i = 0; i < pmcf->modules->nelts; i++) { embedding[2 * i + 1] = "-I"; embedding[2 * i + 2] = (char *) m[i].data; } } embedding[n++] = "-Mnginx"; embedding[n++] = "-e"; embedding[n++] = "0"; n = perl_parse(perl, ngx_http_perl_xs_init, n, embedding, NULL); if (n != 0) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_parse() failed: %d", n); goto fail; } sv = get_sv("nginx::VERSION", FALSE); ver = SvPV(sv, len); if (ngx_strcmp(ver, NGINX_VERSION) != 0) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "version " NGINX_VERSION " of nginx.pm is required, " "but %s was found", ver); goto fail; } if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log) != NGX_OK) { goto fail; } } return perl; fail: (void) perl_destruct(perl); perl_free(perl); return NULL; }
static char * ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf) { ngx_str_t *m; ngx_uint_t i; #if (NGX_HAVE_PERL_MULTIPLICITY) ngx_pool_cleanup_t *cln; cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { return NGX_CONF_ERROR; } #endif #ifdef NGX_PERL_MODULES if (pmcf->modules == NGX_CONF_UNSET_PTR) { pmcf->modules = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t)); if (pmcf->modules == NULL) { return NGX_CONF_ERROR; } m = ngx_array_push(pmcf->modules); if (m == NULL) { return NGX_CONF_ERROR; } ngx_str_set(m, NGX_PERL_MODULES); } #endif if (pmcf->modules != NGX_CONF_UNSET_PTR) { m = pmcf->modules->elts; for (i = 0; i < pmcf->modules->nelts; i++) { if (ngx_conf_full_name(cf->cycle, &m[i], 0) != NGX_OK) { return NGX_CONF_ERROR; } } } #if !(NGX_HAVE_PERL_MULTIPLICITY) if (perl) { if (ngx_set_environment(cf->cycle, NULL) == NULL) { return NGX_CONF_ERROR; } if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log) != NGX_OK) { return NGX_CONF_ERROR; } pmcf->perl = perl; pmcf->nginx = nginx_stash; return NGX_CONF_OK; } #endif if (nginx_stash == NULL) { PERL_SYS_INIT(&ngx_argc, &ngx_argv); } pmcf->perl = ngx_http_perl_create_interpreter(cf, pmcf); if (pmcf->perl == NULL) { return NGX_CONF_ERROR; } pmcf->nginx = nginx_stash; #if (NGX_HAVE_PERL_MULTIPLICITY) cln->handler = ngx_http_perl_cleanup_perl; cln->data = pmcf->perl; #else perl = pmcf->perl; #endif return NGX_CONF_OK; }
/*用新的子进程启动新版本的nginx进程*/ ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) { char **env, *var; u_char *p; ngx_uint_t i, n; ngx_pid_t pid; ngx_exec_ctx_t ctx; ngx_core_conf_t *ccf; ngx_listening_t *ls; ngx_memzero(&ctx, sizeof(ngx_exec_ctx_t)); ctx.path = argv[0]; ctx.name = "new binary process"; ctx.argv = argv; n = 2; env = ngx_set_environment(cycle, &n); if (env == NULL) { return NGX_INVALID_PID; } /* * cycle->listening.nelts * (NGX_INT32_LEN + 1)从下面赋值地方可以看出是两个监听socket之间有';',所以需要+1; * 申请内存的时候额外'+2'多申请2个字节内存,从下面拷贝NGINX_VAR时候可以看出多了个'='号,还有就是结尾的'\0'; */ var = ngx_alloc(sizeof(NGINX_VAR) + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2, cycle->log); if (var == NULL) { ngx_free(env); return NGX_INVALID_PID; } /*下面执行的是生成环境变量"NGINX"用以传递老版本nginx监听的端口*/ p = ngx_cpymem(var, NGINX_VAR "=", sizeof(NGINX_VAR)); ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { p = ngx_sprintf(p, "%ud;", ls[i].fd); } *p = '\0'; env[n++] = var; //将刚生成的"NGINX"环境变量放在总的环境变量之后 /*申请额外的内存用于新的nginx进程修改名字使用*/ #if (NGX_SETPROCTITLE_USES_ENV) /* allocate the spare 300 bytes for the new binary process title */ env[n++] = "SPARE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; #endif env[n] = NULL; #if (NGX_DEBUG) { char **e; for (e = env; *e; e++) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "env: %s", *e); } } #endif ctx.envp = (char *const *) env; /*获取核心模块存储配置项的结构体指针*/ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); /*重命名nginx.pid*/ if (ngx_rename_file(ccf->pid.data, ccf->oldpid.data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_rename_file_n " %s to %s failed " "before executing new binary process \"%s\"", ccf->pid.data, ccf->oldpid.data, argv[0]); ngx_free(env); ngx_free(var); return NGX_INVALID_PID; } /*执行新版本的nginx程序,返回的是用来执行系统调用execve的子进程的id,也是新版本nginx进程的id*/ pid = ngx_execute(cycle, &ctx); if (pid == NGX_INVALID_PID) { if (ngx_rename_file(ccf->oldpid.data, ccf->pid.data) //升级失败,回退nginx.pid文件 == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_rename_file_n " %s back to %s failed after " "an attempt to execute new binary process \"%s\"", ccf->oldpid.data, ccf->pid.data, argv[0]); } } ngx_free(env); ngx_free(var); return pid; }
// main()函数里调用,仅启动一个进程,没有fork // master_process off; void ngx_single_process_cycle(ngx_cycle_t *cycle) { ngx_uint_t i; if (ngx_set_environment(cycle, NULL) == NULL) { /* fatal */ exit(2); } // 调用所有模块的init_process,即进程启动时hook for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } } } // 无限循环,对外提供服务 // ngx_signal_handler处理unix信号 // 收到信号后设置ngx_quit/ngx_sigalrm/ngx_reconfigue等全局变量 // 由无限循环检查这些变量再处理 for ( ;; ) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); // 处理事件的核心函数, event模块里 // 处理socket读写事件和定时器事件 // 获取负载均衡锁,监听端口接受连接 // 调用epoll模块的ngx_epoll_process_events // 然后处理超时事件和在延后队列里的所有事件 // nginx大部分的工作量都在这里 ngx_process_events_and_timers(cycle); // 检查是否处于退出状态 // 这里不使用ngx_exiting变量,直接关闭端口退出 if (ngx_terminate || ngx_quit) { // 所有模块的退出hook for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->exit_process) { ngx_modules[i]->exit_process(cycle); } } // 删除pid,模块清理,关闭监听端口 // 内部直接exit(0)退出 ngx_master_process_exit(cycle); } // 重新配置,以当前cycle重新初始化,即reload if (ngx_reconfigure) { ngx_reconfigure = 0; //标志量清零 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; } // 重新打开所有文件 if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, (ngx_uid_t) -1); } } // 无限循环,对外提供服务 }
// worker进程,cachemanager进程和cacheloader进程的初始化函数 static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) { sigset_t set; uint64_t cpu_affinity; ngx_int_t n; ngx_uint_t i; struct rlimit rlmt; ngx_core_conf_t *ccf; ngx_listening_t *ls; if (ngx_set_environment(cycle, NULL) == NULL) { /* fatal */ exit(2); } ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); // 设置worker进程的nice值,cachemanager cacheloader进程不会设置 if (worker >= 0 && ccf->priority != 0) { if (setpriority(PRIO_PROCESS, 0, ccf->priority) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setpriority(%d) failed", ccf->priority); } } // 设置进程最多可以打开的fd数量 if (ccf->rlimit_nofile != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile; rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile; if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_NOFILE, %i) failed", ccf->rlimit_nofile); } } // 设置这个进程独立于系统的coredump属性 if (ccf->rlimit_core != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_core; rlmt.rlim_max = (rlim_t) ccf->rlimit_core; if (setrlimit(RLIMIT_CORE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_CORE, %O) failed", ccf->rlimit_core); } } #ifdef RLIMIT_SIGPENDING if (ccf->rlimit_sigpending != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_sigpending; rlmt.rlim_max = (rlim_t) ccf->rlimit_sigpending; if (setrlimit(RLIMIT_SIGPENDING, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_SIGPENDING, %i) failed", ccf->rlimit_sigpending); } } #endif // 如果设置了user指令,而且使用root权限启动会在这里改变进程所属的用户和组 if (geteuid() == 0) { if (setgid(ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setgid(%d) failed", ccf->group); /* fatal */ exit(2); } if (initgroups(ccf->username, ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "initgroups(%s, %d) failed", ccf->username, ccf->group); } if (setuid(ccf->user) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setuid(%d) failed", ccf->user); /* fatal */ exit(2); } } if (worker >= 0) { // 获取这个worker对应的CPU号 cpu_affinity = ngx_get_cpu_affinity(worker); // 绑定这个worker对应的CPU。 if (cpu_affinity) { ngx_setaffinity(cpu_affinity, cycle->log); } } #if (NGX_HAVE_PR_SET_DUMPABLE) /* allow coredump after setuid() in Linux 2.4.x */ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "prctl(PR_SET_DUMPABLE) failed"); } #endif // 设置工作目录 if (ccf->working_directory.len) { if (chdir((char *) ccf->working_directory.data) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "chdir(\"%s\") failed", ccf->working_directory.data); /* fatal */ exit(2); } } sigemptyset(&set); // 把父进程设置为阻塞的信号重新设置为可接收状态。 if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } // 设置随机数种子。 srandom((ngx_pid << 16) ^ ngx_time()); /* * disable deleting previous events for the listening sockets because * in the worker processes there are no events at all at this point */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].previous = NULL; } // 调用每个模块的init_process函数 for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } } } // 关闭其他子进程与maser进程通信的unix套接字 for (n = 0; n < ngx_last_process; n++) { if (ngx_processes[n].pid == -1) { continue; } if (n == ngx_process_slot) { continue; } if (ngx_processes[n].channel[1] == -1) { continue; } if (close(ngx_processes[n].channel[1]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); } } // 关闭unix套接字对的父进程端套接字 if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); } #if 0 ngx_last_process = 0; #endif // 将这个进程接收父进程消息套接字的接收事件放到事件模型中, // 并将回调函数设置为ngx_channel_handler if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT, ngx_channel_handler) == NGX_ERROR) { /* fatal */ exit(2); } }