/*工作进程的具体实现*/ 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; /*工作进程初始化,主要是根据cycle中的信息初始化一些设置,以及将监听管道的handler加入到event中*/ ngx_worker_process_init(cycle, worker); /*设置工作进程标题*/ ngx_setproctitle("worker process"); for ( ;; ) { if (ngx_exiting) { ngx_event_cancel_timers(); if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) { 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"); /*处理网络请求事件,这个函数是事件驱动机制的核心,既会处理普通的网络事件,也会处理定时器事件,它们分别被放在不同的事件队列种*/ 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_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); } } }
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; /* worker进程的初始化工作 */ ngx_worker_process_init(cycle, worker); ngx_setproctitle("worker process"); /* worker进程的主循环 */ for ( ;; ) { /* 处理nginx退出 */ if (ngx_exiting) { ngx_event_cancel_timers(); if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) { 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"); /* 网络事件处理函数 */ 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_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); } } }
static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) { ngx_cache_manager_ctx_t *ctx = data; void *ident[4]; ngx_event_t ev; /* * Set correct process type since closing listening Unix domain socket * in a master process also removes the Unix domain socket file. */ ngx_process = NGX_PROCESS_HELPER; ngx_close_listening_sockets(cycle); /* Set a moderate number of connections for a helper process. */ cycle->connection_n = 512; // 读取核心配置,设置cpu优先级,core dump信息,unix运行的group/user // 切换工作路径,根据pid设置随机数种子 // 调用所有模块的init_process,让模块进程初始化 ngx_worker_process_init(cycle, -1); ngx_memzero(&ev, sizeof(ngx_event_t)); ev.handler = ctx->handler; ev.data = ident; ev.log = cycle->log; ident[3] = (void *) -1; ngx_use_accept_mutex = 0; ngx_setproctitle(ctx->name); ngx_add_timer(&ev, ctx->delay); for ( ;; ) { if (ngx_terminate || ngx_quit) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); exit(0); } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, -1); } // 处理事件的核心函数, event模块里 // 处理socket读写事件和定时器事件 // 获取负载均衡锁,监听端口接受连接 // 调用epoll模块的ngx_epoll_process_events // 然后处理超时事件和在延后队列里的所有事件 // nginx大部分的工作量都在这里 ngx_process_events_and_timers(cycle); } }
/* 缓存管理进程 */ static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) { ngx_cache_manager_ctx_t *ctx = data; void *ident[4]; ngx_event_t ev; /* * Set correct process type since closing listening Unix domain socket * in a master process also removes the Unix domain socket file. */ ngx_process = NGX_PROCESS_HELPER; /* 缓存进程不需要监听 */ ngx_close_listening_sockets(cycle); /* Set a moderate number of connections for a helper process. */ cycle->connection_n = 512; ngx_worker_process_init(cycle, -1); ngx_memzero(&ev, sizeof(ngx_event_t)); ev.handler = ctx->handler; ev.data = ident; ev.log = cycle->log; ident[3] = (void *) -1; ngx_use_accept_mutex = 0; ngx_setproctitle(ctx->name); ngx_add_timer(&ev, ctx->delay); for ( ;; ) { if (ngx_terminate || ngx_quit) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); exit(0); } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, -1); } /* 处理时钟和事件 */ ngx_process_events_and_timers(cycle); } }
void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx) { ngx_uint_t i; #if 0 ngx_setproctitle("single worker process"); #endif ngx_init_temp_number(); 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(cycle); if (ngx_terminate || ngx_quit) { ngx_master_exit(cycle, ctx); } if (ngx_reconfigure) { ngx_reconfigure = 0; ngx_log_error(NGX_LOG_INFO, 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_INFO, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, (ngx_uid_t) -1); } } }
static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) { ngx_cache_manager_ctx_t *ctx = data; void *ident[4]; ngx_event_t ev; cycle->connection_n = 512; ngx_process = NGX_PROCESS_HELPER; ngx_worker_process_init(cycle, 0); ngx_close_listening_sockets(cycle); ngx_memzero(&ev, sizeof(ngx_event_t)); ev.handler = ctx->handler; ev.data = ident; ev.log = cycle->log; ident[3] = (void *) -1; ngx_use_accept_mutex = 0; ngx_setproctitle(ctx->name); ngx_add_timer(&ev, ctx->delay); for ( ;; ) { if (ngx_terminate || ngx_quit) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); exit(0); } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, -1); } ngx_process_events_and_timers(cycle); } }
/*启动nginx,主要有以下几步工作: 1.主进程设置信号阻塞 2.设置进程标题 3.启动worker进程 4.启动缓存索引重建进程和管理进程 5.主进程循环处理信号 */ 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; //设置信号阻塞,屏蔽一系列信号,防止被打扰,具体见《apue》 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); size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); 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); //master进程获取core模块配置,ccf中有要创建多少个worker的设定 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); //启动worker,这时已经有了worker进程 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); //创建有关cache的子进程 //信号处理是nginx服务器主进程在服务器运行期间的主要工作,通过一个for循环来实现对信号的循环处理。 ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; for ( ;; ) { //delay用来等待子进程退出的时间,由于我们接受到SIGINT信号后,我们需要先发送信号给子进程, //而子进程的退出需要一定的时间,超时时如果子进程已退出,我们父进程就直接退出, //否则发送sigkill信号给子进程(强制退出),然后再退出。 if (delay) { if (ngx_sigalrm) { sigio = 0; delay *= 2; ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %d", 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); //调用这个将master进程挂起来 ngx_time_update(); //更新缓冲时间 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); //ngx_reap为1,说明有子进程已经退出 if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); //这个里面处理退出的子进程(有的worker异常退出,这时我们就需要重启这个worker ),如果所有子进程都退出则会返回0. live = ngx_reap_children(cycle); } //如果没有存活的子进程,并且收到了ngx_terminate或者ngx_quit信号,则master退出。 if (!live && (ngx_terminate || ngx_quit)) { ngx_master_process_exit(cycle); //master退出 } //收到了sigint信号 if (ngx_terminate) { //设置延时 if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = ccf->worker_processes + 2 /* cache processes */; if (delay > 1000) { //如果超时,则强制杀死worker ngx_signal_worker_processes(cycle, SIGKILL); } else { //负责发送sigint给worker,让它退出 ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } continue; } //收到quit信号 if (ngx_quit) { //发送给worker 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) { //关闭所有socket 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; } //收到需要reconfig的信号 if (ngx_reconfigure) { ngx_reconfigure = 0; //判断是否热代码替换后的新的代码还在运行中(也就是还没退出当前的master)。如果还在运行中,则不需要重新初始化config //ngx_new_binary表示程序本身需要升级,但不需要重新初始化nginx配置,直接调用ngx_start_wroker_process 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"); //重新初始化config,并重新启动新的worker 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); 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"); //进行热代码替换,这里是调用execve来执行新的代码 ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); } //接受到停止accept连接,其实也就是worker退出(有区别的是,这里master不需要退出) if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; //给worker发送信号 ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } //end of for 信号处理结束 }
/*[p] 工作进程要执行的具体工作*/ static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { ngx_uint_t i; ngx_connection_t *c; ngx_process = NGX_PROCESS_WORKER; //初始化worker进程 ngx_worker_process_init(cycle, 1); //[p]设置工作进程标题 ngx_setproctitle("worker process"); #if (NGX_THREADS) { ngx_int_t n; ngx_err_t err; ngx_core_conf_t *ccf; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ngx_threads_n) { if (ngx_init_threads(ngx_threads_n, ccf->thread_stack_size, cycle) == NGX_ERROR) { /* fatal */ exit(2); } err = ngx_thread_key_create(&ngx_core_tls_key); if (err != 0) { ngx_log_error(NGX_LOG_ALERT, cycle->log, err, ngx_thread_key_create_n " failed"); /* fatal */ exit(2); } for (n = 0; n < ngx_threads_n; n++) { ngx_threads[n].cv = ngx_cond_init(cycle->log); if (ngx_threads[n].cv == NULL) { /* fatal */ exit(2); } if (ngx_create_thread((ngx_tid_t *) &ngx_threads[n].tid, ngx_worker_thread_cycle, (void *) &ngx_threads[n], cycle->log) != 0) { /* fatal */ exit(2); } } } } #endif for ( ;; ) { //ngx_exiting是当收到master的quit命令(SIGQUIT信号)后,设置为1,然后等待其他资源退出 if (ngx_exiting) { c = cycle->connections; // worker进程退出前,先处理完每个connection上已经发生的事件 for (i = 0; i < cycle->connection_n; i++) { /* THREAD: lock */ if (c[i].fd != -1 && c[i].idle) { c[i].close = 1; c[i].read->handler(c[i].read); } } //定时器超时则退出worker; 处理完所有事件,worker进程退出 if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) { 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"); // 这里是worker进程处理事件的核心。 ngx_process_events_and_timers(cycle); //收到shutdown命令(SIGINT信号)则worker直接退出 if (ngx_terminate) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); ngx_worker_process_exit(cycle); } //收到quit命令(SIGQUIT信号) 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) { //关闭socket,然后设置退出标志 ngx_close_listening_sockets(cycle); ngx_exiting = 1; } } //收到master重新打开log的命令,worker进程收到了SIGUSR1信号 if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, -1); } } }
static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { ngx_int_t worker = (intptr_t) data; ngx_uint_t i; ngx_connection_t *c; ngx_process = NGX_PROCESS_WORKER; ngx_worker = worker; ngx_worker_process_init(cycle, worker); ngx_setproctitle("worker process"); for ( ;; ) { if (ngx_exiting) { c = cycle->connections; for (i = 0; i < cycle->connection_n; i++) { /* THREAD: lock */ if (c[i].fd != -1 && c[i].idle) { c[i].close = 1; c[i].read->handler(c[i].read); } } ngx_event_cancel_timers(); if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) { 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"); 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_close_listening_sockets(cycle); ngx_exiting = 1; } } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, -1); } } }
/* * 主要工作: * 主进程设置信号堵塞 * 设置进程标题 * 启动worker进程 * 启动缓存索引重建(cache loader)进程及管理(Cache Manager)进程 * 主进程循环处理信号 * */ 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; /*将下列信号添加到信号集set中*/ 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)); /*将信号集set覆盖为当前进程的信号集*/ if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); /*开始设置进程标题*/ /*计算进程标题的总体长度*/ 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); /*启动工作进程*/ ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); /*启动缓存索引重建进程,该进程在整个Nginx服务器运行过程中只存在很短的时间,主要用来遍历磁盘上的缓存数据,在内存中建立数据索引,提高Nginx服务器检索缓存的效率*/ ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; 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); /*如果有工作进程异常退出,则调用ngx_reap_children()重启该工作进程*/ if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); /*重启工作进程*/ live = ngx_reap_children(cycle); } /*如果主进程接收到的是NGX_CMD_TERMINATE信号、SIGTERM信号、SIGINT信号(ngx_terminate=1)或者收到的是NGX_CMD_QUIT信号、SIGQUIT信号(ngx_quit=1),并且工作进程退出,则主进程调用ngx_master_process_exit()函数退出*/ if (!live && (ngx_terminate || ngx_quit)) { ngx_master_process_exit(cycle); } /*处理SIGINT信号*/ if (ngx_terminate) { if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } /*包括两个管理内存索引的进程*/ sigio = ccf->worker_processes + 2 /* cache processes */; /*超时1s,直接终止工作进程*/ if (delay > 1000) { ngx_signal_worker_processes(cycle, SIGKILL); } else { /*工作进程正常退出*/ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } continue; } /*处理SIGQUIT信号*/ if (ngx_quit) { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); /*关闭所有的socket*/ 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; } /*处理SIGHUP信号*/ if (ngx_reconfigure) { ngx_reconfigure = 0; /*热升级(平滑升级,不用停止服务)*/ /*当ngx_new_binary=1时,说明主进程本身需要升级,但是不需要重新初始化Nginx配置,因此可以直接调用ngx_start_worker_processes()函数重启工作进程和缓存索引管理进程*/ /*当ngx_new_binary!=1时,则说明时Nginx服务器配置改变,需要调用ngx_init_cycle()函数初始化Nginx配置,并按照新的配置启动工作进程和缓存索引管理进程,向之前的所有进程发送NGX_SHUTDOWN_SIGNAL信号,这样旧实现了Nginx服务器的平滑升级*/ 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; } /*读取Nginx配置*/ 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; /*关闭旧的Nginx进程*/ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } /*重启工作进程*/ /*只有一种情况可以将ngx_restart变量赋值为1,就是在调用ngx_reap_children()函数重启工作进程的时候,当主进程接收到NGX_NOACCEPT_SIGNAL信号(不再接收请求,退出工作进程)时,会设置全局变量ngx_noaccept为1,然后再Nginx初始化信号设置时会将全局变量ngx_noaccepting设置为1,于是在ngx_reap_children()函数中就会将ngx_restart变量设置为1,进而执行下面的if语句中的代码,重启工作进程和缓存索引管理进程*/ 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; } /*处理SIGUSR1信号,该信号用于重新打开日志文件*/ 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)); } /*处理SIGUSR2信号,热代码切换*/ 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); } /*处理NGX_NOACCEPT_SIGNAL信号*/ if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; /*退出工作进程,不再接收网络请求*/ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
static void ngx_procs_cycle(ngx_cycle_t *cycle, void *data) { ngx_int_t rc; ngx_uint_t i; ngx_module_t *module; ngx_proc_args_t *args; ngx_proc_conf_t *cpcf; ngx_connection_t *c; ngx_proc_module_t *ctx; args = data; module = args->module; cpcf = args->proc_conf; ctx = module->ctx; ngx_process = NGX_PROCESS_PROC; ngx_setproctitle((char *) ctx->name.data); ngx_msleep(cpcf->delay_start); ngx_procs_process_init(cycle, ctx, cpcf->priority); ngx_close_listening_sockets(cycle); ngx_use_accept_mutex = 0; for ( ;; ) { if (ngx_exiting || ngx_quit) { ngx_exiting = 1; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "process %V gracefully shutting down", &ctx->name); ngx_setproctitle("processes are shutting down"); c = cycle->connections; for (i = 0; i < cycle->connection_n; i++) { if (c[i].fd != -1 && c[i].idle) { c[i].close = 1; c[i].read->handler(c[i].read); } } ngx_procs_process_exit(cycle, ctx); } if (ngx_terminate) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "process %V exiting", &ctx->name); ngx_procs_process_exit(cycle, ctx); } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, -1); } if (ctx->loop) { rc = ctx->loop(cycle); if (rc != NGX_OK) { break; } } ngx_time_update(); ngx_process_events_and_timers(cycle); } ngx_procs_process_exit(cycle, ctx); }
/* * master进程主循环 */ 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)); /* 进程屏蔽set中的信号 */ if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); 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); /* 启动work进程 */ ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; /* 标记是否还有活着的子进程*/ for ( ;; ) { //delay用来设置等待worker终止的时间,master接收了终止信号后 //首先发送终止信号给worker,然后等待work终止 if (delay) { if (ngx_sigalrm) { sigio = 0; delay *= 2; ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %d", 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; /* 应为itv.it_interval 为0 定时器只触发一次 */ 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返回 */ sigsuspend(&set); ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); /* 当master收到work进程结束信号,回收子进程 */ if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); live = ngx_reap_children(cycle); } /* live为1表示有子进程在运行,为0代表,所有子进程都退出了 */ if (!live && (ngx_terminate || ngx_quit)) { /* 没有子进程了 且收到终止或退出信号*/ ngx_master_process_exit(cycle); } /* master收到终止信号*/ if (ngx_terminate) { if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = ccf->worker_processes + 2 /* cache processes */; if (delay > 1000) { /* 延时已到,给所有worker发送SIGKILL信号,强制杀死worker */ ngx_signal_worker_processes(cycle, SIGKILL); } else { /* 通知work进程终止 */ 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; } if (ngx_reconfigure) { ngx_reconfigure = 0; /* 代码已被替换,重启worker,不需要重新初始化配置。 */ 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 = 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)); } /* 重新创建work进程 当ngx_noaccepting==1时,会把ngx_restart设为1,重启worker */ 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); } /* 通知work进程停止accept新连接,work进程退出 */ if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { sigset_t set; ngx_err_t err; ngx_int_t n; ngx_uint_t i; struct timeval tv; ngx_listening_t *ls; ngx_core_conf_t *ccf; ngx_connection_t *c; ngx_gettimeofday(&tv); ngx_start_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000 + tv.tv_usec / 1000; ngx_old_elapsed_msec = 0; ngx_elapsed_msec = 0; ngx_process = NGX_PROCESS_WORKER; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ccf->group != (gid_t) NGX_CONF_UNSET) { if (setgid(ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setgid(%d) failed", ccf->group); /* fatal */ exit(2); } } if (ccf->user != (uid_t) NGX_CONF_UNSET) { if (setuid(ccf->user) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setuid(%d) failed", ccf->user); /* fatal */ exit(2); } } #if (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 sigemptyset(&set); if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } ngx_init_temp_number(); /* * 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].remain = 0; } 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() failed"); } } if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() 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); } ngx_setproctitle("worker process"); for ( ;; ) { if (ngx_exiting && ngx_event_timer_rbtree == &ngx_event_timer_sentinel) { ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting"); /* * we do not destroy cycle->pool here because a signal handler * that uses cycle->log can be called at this point */ exit(0); } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); ngx_process_events(cycle); if (ngx_terminate) { ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting"); /* * we do not destroy cycle->pool here because a signal handler * that uses cycle->log can be called at this point */ exit(0); } if (ngx_quit) { ngx_quit = 0; ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "gracefully shutting down"); ngx_setproctitle("worker process is shutting down"); if (!ngx_exiting) { ngx_close_listening_sockets(cycle); ngx_exiting = 1; } } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopen logs"); ngx_reopen_files(cycle, -1); } } }
static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { ngx_int_t worker = (intptr_t) data; ngx_uint_t i; ngx_connection_t *c; ngx_process = NGX_PROCESS_WORKER; ngx_worker_process_init(cycle, worker); ngx_setproctitle("worker process"); #if (NGX_THREADS) { ngx_int_t n; ngx_err_t err; ngx_core_conf_t *ccf; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ngx_threads_n) { if (ngx_init_threads(ngx_threads_n, ccf->thread_stack_size, cycle) == NGX_ERROR) { /* fatal */ exit(2); } err = ngx_thread_key_create(&ngx_core_tls_key); if (err != 0) { ngx_log_error(NGX_LOG_ALERT, cycle->log, err, ngx_thread_key_create_n " failed"); /* fatal */ exit(2); } for (n = 0; n < ngx_threads_n; n++) { ngx_threads[n].cv = ngx_cond_init(cycle->log); if (ngx_threads[n].cv == NULL) { /* fatal */ exit(2); } if (ngx_create_thread((ngx_tid_t *) &ngx_threads[n].tid, ngx_worker_thread_cycle, (void *) &ngx_threads[n], cycle->log) != 0) { /* fatal */ exit(2); } } } } #endif for ( ;; ) { if (ngx_exiting) { c = cycle->connections; for (i = 0; i < cycle->connection_n; i++) { /* THREAD: lock */ if (c[i].fd != -1 && c[i].idle) { c[i].close = 1; c[i].read->handler(c[i].read); } } if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) { 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"); 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_close_listening_sockets(cycle); ngx_exiting = 1; } } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, -1); } } }
void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx) { char *title; u_char *p; size_t size; ngx_int_t i; sigset_t set; struct timeval tv; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; 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); size = sizeof(master_process); for (i = 0; i < ctx->argc; i++) { size += ngx_strlen(ctx->argv[i]) + 1; } title = ngx_palloc(cycle->pool, size); p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ctx->argc; i++) { *p++ = ' '; p = ngx_cpystrn(p, (u_char *) ctx->argv[i], size); } ngx_setproctitle(title); ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_new_binary = 0; delay = 0; live = 1; for ( ;; ) { if (delay) { delay *= 2; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "temination cycle: %d", 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_gettimeofday(&tv); ngx_time_update(tv.tv_sec); ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up"); if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap childs"); live = ngx_reap_childs(cycle); } if (!live && (ngx_terminate || ngx_quit)) { ngx_master_exit(cycle, ctx); } if (ngx_terminate) { if (delay == 0) { delay = 50; } 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)); continue; } if (ngx_timer) { ngx_timer = 0; ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } if (ngx_reconfigure) { ngx_reconfigure = 0; if (ngx_new_binary) { ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "start new workers"); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_noaccepting = 0; continue; } ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reconfiguring"); 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); 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); live = 1; } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_INFO, 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_INFO, cycle->log, 0, "changing binary"); ngx_new_binary = ngx_exec_new_binary(cycle, ctx->argv); } if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
// 传递给ngx_spawn_process(),是worker进程的核心功能 // data实际上是进程号, (void *) (intptr_t) i static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { // 把data再转换为进程序号 ngx_int_t worker = (intptr_t) data; ngx_uint_t i; ngx_connection_t *c; // 设置进程状态 ngx_process = NGX_PROCESS_WORKER; // nginx 1.9.x //ngx_worker = worker; // 读取核心配置,设置cpu优先级,core dump信息,unix运行的group/user // 切换工作路径,根据pid设置随机数种子 // 调用所有模块的init_process,让模块进程初始化 ngx_worker_process_init(cycle, worker); // 设置进程名字 ngx_setproctitle("worker process"); // 无限循环,处理事件和信号 for ( ;; ) { // 进程正在退出,即quit // 收到了-s quit,关闭监听端口后再停止进程(优雅关闭) if (ngx_exiting) { c = cycle->connections; for (i = 0; i < cycle->connection_n; i++) { /* THREAD: lock */ if (c[i].fd != -1 && c[i].idle) { c[i].close = 1; c[i].read->handler(c[i].read); } } // 取消定时器,调用handler处理 ngx_event_cancel_timers(); // 定时器红黑树为空,即已经没有任何事件 // 否则表示还有事件未处理,暂不退出 if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); // 调用所有模块的exit_process,进程结束hook // 内部直接exit(0)退出 ngx_worker_process_exit(cycle); } } 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); // 收到了-s stop,直接停止进程 if (ngx_terminate) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); // 调用所有模块的exit_process,进程结束hook // 内部直接exit(0)退出 ngx_worker_process_exit(cycle); } // 收到了-s quit,关闭监听端口后再停止进程(优雅关闭) 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) { // in ngx_connection.c // 遍历监听端口列表,逐个删除监听事件 // 不再接受新的连接请求 ngx_close_listening_sockets(cycle); // 设置ngx_exiting标志,继续走循环 // 等所有事件都处理完了才能真正退出 ngx_exiting = 1; } } // 收到了-s reopen,重新打开文件 if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, -1); } } // 无限循环,处理事件和信号 }
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; struct rlimit rlmt; 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); size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); 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); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); /* The directives such as "user", "rlimit_core", etc. should also be * effective on master process. Changed by Zimbra */ 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); } } /* end change by Zimbra */ ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; 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: %d", 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); } 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; } if (ngx_reconfigure) { ngx_reconfigure = 0; 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 = 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); 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)); } } }
// main()函数里调用,启动worker进程 // 监听信号 // 核心操作是sigsuspend,暂时挂起进程,不占用CPU,只有收到信号时才被唤醒 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; // 添加master进程关注的信号 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); // static u_char master_process[] = "master process"; // 计算master进程的名字 size = sizeof(master_process); // 加上命令行参数,注意使用的是nginx拷贝后的参数 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); // 取core模块配置 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); // 启动worker进程,数量由配置决定,即worker_processes指令 // #define NGX_PROCESS_RESPAWN -3 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); // cache进程 ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; //延时的计数器 sigio = 0; live = 1; //是否有存活的子进程 // master进程的无限循环,只处理信号 // 主要调用ngx_signal_worker_processes()发送信号 // ngx_start_worker_processes()产生新子进程 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: %d", 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; // 系统调用,设置发送SIGALRM的时间间隔 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,暂时挂起进程,不占用CPU,只有收到信号时才被唤醒 // 收到SIGALRM就检查子进程是否都已经处理完了 sigsuspend(&set); // 更新一下时间 ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); // 子进程可能发生了意外结束 // 在os/unix/ngx_process.c ngx_signal_handler()里设置 if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); // 重新产生子进程 live = ngx_reap_children(cycle); } // 无存活子进程且收到stop/quit信号 if (!live && (ngx_terminate || ngx_quit)) { // 删除pid,模块清理,关闭监听端口 // 内部直接exit(0)退出 ngx_master_process_exit(cycle); } // 收到了-s stop,停止进程 if (ngx_terminate) { // 延时等待子进程关闭 if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = ccf->worker_processes + 2 /* cache processes */; if (delay > 1000) { // 超时太多,直接发送SIGKILL杀死进程 // master进程调用,遍历ngx_processes数组,用kill发送信号 ngx_signal_worker_processes(cycle, SIGKILL); } else { // master进程调用,遍历ngx_processes数组,用kill发送信号 // 走到worker进程的ngx_signal_handler() // 然后再是ngx_worker_process_cycle()的ngx_terminate ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } // 等待SIGALRM信号,检查子进程是否都结束 continue; } // 收到了-s quit,关闭监听端口后再停止进程(优雅关闭) if (ngx_quit) { // master进程调用,遍历ngx_processes数组,用kill发送信号 // 走到worker进程的ngx_signal_handler() // 然后再是ngx_worker_process_cycle()的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; } // 收到了-s reload重新配置 if (ngx_reconfigure) { ngx_reconfigure = 0; // 启动新的nginx二进制 if (ngx_new_binary) { // 启动worker进程,数量由配置决定,即worker_processes指令 // 调用时传递的是#define NGX_PROCESS_RESPAWN -3 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"); // nginx可执行程序不变,以当前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); // 启动worker进程,数量由配置决定,即worker_processes指令 // 调用时传递的是#define NGX_PROCESS_JUST_RESPAWN -2 // 这样新启动的进程不会发送shutdown信号 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); ngx_start_cache_manager_processes(cycle, 1); /* allow new processes to start */ // 阻塞等待100毫秒 ngx_msleep(100); // 设置进程存活标志 live = 1; // 关闭原来的worker进程 // 新启动的进程不会发送shutdown信号 // master进程调用,遍历ngx_processes数组,用kill发送信号 // 走到worker进程的ngx_signal_handler() // 然后再是ngx_worker_process_cycle()的ngx_quit ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } if (ngx_restart) { ngx_restart = 0; // 启动worker进程,数量由配置决定,即worker_processes指令 // 调用时传递的是#define NGX_PROCESS_RESPAWN -3 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)); } } //master进程无限循环结束 }
static void ngx_pipe_log(ngx_cycle_t *cycle, ngx_open_pipe_t *op) { ngx_int_t n_bytes_read; u_char *read_buf; size_t read_buf_len = 65536; ngx_fd_t log_fd = NGX_INVALID_FILE; #ifdef T_PIPE_NO_DISPLAY size_t title_len; #endif ngx_pipe_rollback_conf_t rbcf; ngx_file_info_t sb; size_t one_day = 24 * 60 * 60; ngx_pid = ngx_getpid(); rbcf.last_open_time = 0; rbcf.last_suit_time = 0; rbcf.log_size = 0; if (ngx_pipe_rollback_parse_args(cycle, op, &rbcf) != NGX_OK) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "log rollback parse error"); return; } read_buf = ngx_pcalloc(cycle->pool, read_buf_len); if (read_buf == NULL) { return; } //set title ngx_setproctitle((char *) op->cmd); #ifdef T_PIPE_NO_DISPLAY title_len = ngx_strlen(ngx_os_argv[0]); #if (NGX_SOLARIS) #else ngx_memset((u_char *) ngx_os_argv[0], NGX_SETPROCTITLE_PAD, title_len); ngx_cpystrn((u_char *) ngx_os_argv[0], op->cmd, title_len); #endif #endif for (;;) { if (ngx_terminate == 1) { return; } n_bytes_read = ngx_read_fd(0, read_buf, read_buf_len); if (n_bytes_read == 0) { return; } if (errno == EINTR) { continue; } else if (n_bytes_read < 0) { return; } rbcf.time_now = ngx_pipe_get_now_sec(); if (NULL != rbcf.suitpath) { if (rbcf.time_now / one_day > rbcf.last_suit_time / one_day) { ngx_pipe_create_suitpath(cycle, &rbcf); } } if (log_fd >= 0) { if (rbcf.interval > 0) { if (((rbcf.time_now - rbcf.adjust_time) / rbcf.interval) > (rbcf.last_open_time / rbcf.interval)) { //need check rollback ngx_close_file(log_fd); log_fd = NGX_INVALID_FILE; ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "need check rollback time [%s]", rbcf.logname); ngx_pipe_do_rollback(cycle, &rbcf); } } } if (log_fd >= 0 && rbcf.log_max_size > 0 && rbcf.log_size >= rbcf.log_max_size) { ngx_close_file(log_fd); log_fd = NGX_INVALID_FILE; ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "need check rollback size [%s] [%d]", rbcf.logname, rbcf.log_size); ngx_pipe_do_rollback(cycle, &rbcf); } /* If there is no log file open then open a new one. * */ if (log_fd < 0) { ngx_pipe_create_subdirs(rbcf.logname, cycle); if (rbcf.interval > 0 && rbcf.last_open_time == 0 && ((rbcf.time_now - rbcf.adjust_time_raw) / rbcf.interval < rbcf.time_now / rbcf.interval)) { /*just check when time is after interval and befor adjust_time_raw, fix when no backup file, do rollback */ //need check last rollback time, because other process may do rollback after when it adjust time more than this process ngx_pipe_get_last_rollback_time(&rbcf); } else { rbcf.last_open_time = ngx_pipe_get_now_sec(); } log_fd = ngx_open_file(rbcf.logname, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, NGX_PIPE_FILE_ACCESS); if (log_fd < 0) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "open [%s] failed", rbcf.logname); return; } if (0 == ngx_fd_info(log_fd, &sb)) { rbcf.log_size = sb.st_size; } } if (ngx_write_fd(log_fd, read_buf, n_bytes_read) != n_bytes_read) { if (errno != EINTR) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "write to [%s] failed", rbcf.logname); return; } } rbcf.log_size += n_bytes_read; } }
// 启动后master进程在这个函数进入死循环 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)); // 让master进程只有在sigsuspend()里才会捕捉参数set里的信号。 if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); // 设置ps命令显示的进程标题 size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); 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进程 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; for ( ;; ) { if (delay) { // 收到退出信号后会使用这个分支, // 作用是定时检查是否还有活跃子进程,如果没有就退出master进程 if (ngx_sigalrm) { sigio = 0; delay *= 2; ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %d", 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) { // master进程的子进程结束时,master进程收到SIGCHLD信号后,ngx_reap被置1。 ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); live = ngx_reap_children(cycle); } if (!live && (ngx_terminate || ngx_quit)) { // 收到退出信号且已经没有活跃子进程后便退出 ngx_master_process_exit(cycle); } if (ngx_terminate) { // 收到SIGINT,SIGTERM信号后,直接关闭nginx, // 首先给子进程发送关闭信号,1秒还没有关完就强制关闭所有子进程 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) { // 收到SIGQUIT信号后,优雅关闭Nginx, // 待所有worker进程将已经连接的请求处理完后在退出 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; } if (ngx_reconfigure) { // 收到SIGHUP信号后,ngx_reconfigure在信号处理函数中被置1,执行让新配置文件生效的操作。 ngx_reconfigure = 0; 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 = 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) { // 好像是平滑升级时,新起的nginx意外退出了,要在把之前nginx的工作进程在重新启动 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) { // 启动新的nignx,使新旧nginx同时工作 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) { // 收到sigwinch信号后优雅关闭所有子进程 ngx_noaccept = 0; ngx_noaccepting = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
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); size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); 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); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; 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: %d", 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); } 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; } if (ngx_reconfigure) { ngx_reconfigure = 0; 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 = 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)); } } }
// http://www.xuebuyuan.com/557917.html // http://blog.csdn.net/lu_ming/article/details/5144427 // http://blog.csdn.net/lengzijian/article/details/7587740 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; // block these signals 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); // set title = "master process" + argv[0] + argv[1] + ... size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); 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); // Start workers and cache_manager ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; 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: %d", 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() temporarily replaces the signal mask of the calling // process with the mask given by mask and then suspends the process // until delivery of a signal whose action is to invoke a // signal handler or to terminate a process. 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); } if (!live && (ngx_terminate || ngx_quit)) { ngx_master_process_exit(cycle); } // on SIGINT set ngx_terminate = 1 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; } if (ngx_reconfigure) { ngx_reconfigure = 0; 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 = 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); // Nginx won't guarantee the new workers will be ready to accept // new connections before sending shutdown signals to old workers. // If the new works takes more than 100ms to startup, then there is // a risk that the old workers are shutdown but new workers are still // not ready, as a result, new connections will be pending until a new // worker is ready to handle. /* 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)); } } }